1 /* File: main-x11.c */
2 
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10 
11 
12 /*
13  * This file helps Angband work with UNIX/X11 computers.
14  *
15  * To use this file, compile with "USE_X11" defined, and link against all
16  * the various "X11" libraries which may be needed.
17  *
18  * See also "main-xaw.c".
19  *
20  * Part of this file provides a user interface package composed of several
21  * pseudo-objects, including "metadpy" (a display), "infowin" (a window),
22  * "infoclr" (a color), and "infofnt" (a font).  Actually, the package was
23  * originally much more interesting, but it was bastardized to keep this
24  * file simple.
25  *
26  * The rest of this file is an implementation of "main-xxx.c" for X11.
27  *
28  * Most of this file is by Ben Harrison (benh@phial.com).
29  */
30 
31 /*
32  * The following shell script can be used to launch Angband, assuming that
33  * it was extracted into "~/Angband", and compiled using "USE_X11", on a
34  * Linux machine, with a 1280x1024 screen, using 6 windows (with the given
35  * characteristics), with gamma correction of 1.8 -> (1 / 1.8) * 256 = 142,
36  * and without graphics (add "-g" for graphics).  Just copy this comment
37  * into a file, remove the leading " * " characters (and the head/tail of
38  * this comment), and make the file executable.
39  *
40  *
41  * #!/bin/csh
42  *
43  * # Describe attempt
44  * echo "Launching angband..."
45  * sleep 2
46  *
47  * # Main window
48  * setenv ANGBAND_X11_FONT_0 10x20
49  * setenv ANGBAND_X11_AT_X_0 5
50  * setenv ANGBAND_X11_AT_Y_0 510
51  *
52  * # Message window
53  * setenv ANGBAND_X11_FONT_1 8x13
54  * setenv ANGBAND_X11_AT_X_1 5
55  * setenv ANGBAND_X11_AT_Y_1 22
56  * setenv ANGBAND_X11_ROWS_1 35
57  *
58  * # Inventory window
59  * setenv ANGBAND_X11_FONT_2 8x13
60  * setenv ANGBAND_X11_AT_X_2 635
61  * setenv ANGBAND_X11_AT_Y_2 182
62  * setenv ANGBAND_X11_ROWS_2 23
63  *
64  * # Equipment window
65  * setenv ANGBAND_X11_FONT_3 8x13
66  * setenv ANGBAND_X11_AT_X_3 635
67  * setenv ANGBAND_X11_AT_Y_3 22
68  * setenv ANGBAND_X11_ROWS_3 12
69  *
70  * # Monster recall window
71  * setenv ANGBAND_X11_FONT_4 6x13
72  * setenv ANGBAND_X11_AT_X_4 817
73  * setenv ANGBAND_X11_AT_Y_4 847
74  * setenv ANGBAND_X11_COLS_4 76
75  * setenv ANGBAND_X11_ROWS_4 11
76  *
77  * # Object recall window
78  * setenv ANGBAND_X11_FONT_5 6x13
79  * setenv ANGBAND_X11_AT_X_5 817
80  * setenv ANGBAND_X11_AT_Y_5 520
81  * setenv ANGBAND_X11_COLS_5 76
82  * setenv ANGBAND_X11_ROWS_5 24
83  *
84  * # The build directory
85  * cd ~/Angband
86  *
87  * # Gamma correction
88  * setenv ANGBAND_X11_GAMMA 142
89  *
90  * # Launch Angband
91  * ./src/angband -mx11 -- -n6 &
92  *
93  */
94 
95 
96 
97 #include "angband.h"
98 
99 
100 #ifdef USE_X11
101 
102 cptr help_x11[] =
103 {
104 	"To use X11",
105 	"-d    Set display name",
106 #ifdef USE_GRAPHICS
107 	"-s    Turn off smoothscaling graphics",
108 	"-b#   Set tileset bitmap",
109 #endif /* USE_GRAPHICS */
110 	"-n#   Number of terms to use",
111 	NULL
112 };
113 
114 
115 #ifndef __MAKEDEPEND__
116 #include <X11/Xlib.h>
117 #include <X11/Xutil.h>
118 #include <X11/keysym.h>
119 #include <X11/keysymdef.h>
120 #include <X11/Xatom.h>
121 #endif /* __MAKEDEPEND__ */
122 
123 
124 /*
125  * Include some helpful X11 code.
126  */
127 #include "maid-x11.h"
128 
129 /*
130  * Hack -- avoid some compiler warnings
131  */
132 #define IGNORE_UNUSED_FUNCTIONS
133 
134 
135 /*
136  * Notes on Colors:
137  *
138  *   1) On a monochrome (or "fake-monochrome") display, all colors
139  *   will be "cast" to "fg," except for the bg color, which is,
140  *   obviously, cast to "bg".  Thus, one can ignore this setting.
141  *
142  *   2) Because of the inner functioning of the color allocation
143  *   routines, colors may be specified as (a) a typical color name,
144  *   (b) a hexidecimal color specification (preceded by a pound sign),
145  *   or (c) by strings such as "fg", "bg", "zg".
146  *
147  *   3) Due to the workings of the init routines, many colors
148  *   may also be dealt with by their actual pixel values.  Note that
149  *   the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
150  *   is not necessarily either black or white.
151  */
152 
153 
154 
155 /**** Generic Types ****/
156 
157 
158 /*
159  * An X11 pixell specifier
160  */
161 typedef unsigned long Pixell;
162 
163 /*
164  * The structures defined below
165  */
166 typedef struct metadpy metadpy;
167 typedef struct infowin infowin;
168 typedef struct infoclr infoclr;
169 typedef struct infofnt infofnt;
170 
171 
172 /*
173  * A structure summarizing a given Display.
174  *
175  *	- The Display itself
176  *	- The default Screen for the display
177  *	- The virtual root (usually just the root)
178  *	- The default colormap (from a macro)
179  *
180  *	- The "name" of the display
181  *
182  *	- The socket to listen to for events
183  *
184  *	- The width of the display screen (from a macro)
185  *	- The height of the display screen (from a macro)
186  *	- The bit depth of the display screen (from a macro)
187  *
188  *	- The black Pixell (from a macro)
189  *	- The white Pixell (from a macro)
190  *
191  *	- The background Pixell (default: black)
192  *	- The foreground Pixell (default: white)
193  *	- The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
194  *
195  *	- Bit Flag: Force all colors to black and white (default: !color)
196  *	- Bit Flag: Allow the use of color (default: depth > 1)
197  *	- Bit Flag: We created 'dpy', and so should nuke it when done.
198  */
199 struct metadpy
200 {
201 	Display *dpy;
202 	Screen *screen;
203 	Window root;
204 	Colormap cmap;
205 
206 	char *name;
207 
208 	int fd;
209 
210 	uint width;
211 	uint height;
212 	uint depth;
213 
214 	Pixell black;
215 	Pixell white;
216 
217 	Pixell bg;
218 	Pixell fg;
219 	Pixell zg;
220 
221 	uint mono:1;
222 	uint color:1;
223 	uint nuke:1;
224 };
225 
226 
227 
228 /*
229  * A Structure summarizing Window Information.
230  *
231  * I assume that a window is at most 30000 pixels on a side.
232  * I assume that the root windw is also at most 30000 square.
233  *
234  *	- The Window
235  *	- The current Input Event Mask
236  *
237  *	- The location of the window
238  *	- The width, height of the window
239  *	- The border width of this window
240  *
241  *	- Byte: 1st Extra byte
242  *
243  *	- Bit Flag: This window is currently Mapped
244  *	- Bit Flag: This window needs to be redrawn
245  *	- Bit Flag: This window has been resized
246  *
247  *	- Bit Flag: We should nuke 'win' when done with it
248  */
249 struct infowin
250 {
251 	Window win;
252 	long mask;
253 
254 	s16b ox, oy;
255 
256 	s16b x, y;
257 	s16b w, h;
258 	u16b b;
259 
260 	byte byte1;
261 
262 	bool mapped;
263 	bool redraw;
264 	bool resize;
265 
266 	bool nuke;
267 };
268 
269 
270 
271 
272 
273 
274 /*
275  * A Structure summarizing Operation+Color Information
276  *
277  *	- The actual GC corresponding to this info
278  *
279  *	- The Foreground Pixell Value
280  *	- The Background Pixell Value
281  *
282  *	- Num (0-15): The operation code (As in Clear, Xor, etc)
283  *	- Bit Flag: The GC is in stipple mode
284  *	- Bit Flag: Destroy 'gc' at Nuke time.
285  */
286 struct infoclr
287 {
288 	GC gc;
289 
290 	Pixell fg;
291 	Pixell bg;
292 
293 	uint code:4;
294 	uint stip:1;
295 	uint nuke:1;
296 };
297 
298 
299 
300 /*
301  * A Structure to Hold Font Information
302  *
303  *	- The 'XFontStruct*' (yields the 'Font')
304  *
305  *	- The font name
306  *
307  *	- The default character width
308  *	- The default character height
309  *	- The default character ascent
310  *
311  *	- Byte: Pixel offset used during fake mono
312  *
313  *	- Flag: Force monospacing via 'wid'
314  *	- Flag: Nuke info when done
315  */
316 struct infofnt
317 {
318 	XFontStruct *info;
319 
320 	cptr name;
321 
322 	s16b wid;
323 	s16b twid;
324 	s16b hgt;
325 	s16b asc;
326 
327 	byte off;
328 
329 	uint mono:1;
330 	uint nuke:1;
331 };
332 
333 
334 
335 
336 /**** Generic Macros ****/
337 
338 
339 
340 /* Set current metadpy (Metadpy) to 'M' */
341 #define Metadpy_set(M) \
342 	Metadpy = M
343 
344 
345 /* Initialize 'M' using Display 'D' */
346 #define Metadpy_init_dpy(D) \
347 	Metadpy_init_2(D,cNULL)
348 
349 /* Initialize 'M' using a Display named 'N' */
350 #define Metadpy_init_name(N) \
351 	Metadpy_init_2((Display*)(NULL),N)
352 
353 /* Initialize 'M' using the standard Display */
354 #define Metadpy_init() \
355 	Metadpy_init_name("")
356 
357 
358 /* Init an infowin by giving father as an (info_win*) (or NULL), and data */
359 #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
360 	Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
361 	                  X,Y,W,H,B,FG,BG)
362 
363 
364 /* Init a top level infowin by pos,size,bord,Colors */
365 #define Infowin_init_top(X,Y,W,H,B,FG,BG) \
366 	Infowin_init_data(None,X,Y,W,H,B,FG,BG)
367 
368 
369 /* Request a new standard window by giving Dad infowin and X,Y,W,H */
370 #define Infowin_init_std(D,X,Y,W,H,B) \
371 	Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
372 
373 
374 /* Set the current Infowin */
375 #define Infowin_set(I) \
376 	(Infowin = (I))
377 
378 
379 /* Set the current Infoclr */
380 #define Infoclr_set(C) \
381 	(Infoclr = (C))
382 
383 
384 #define Infoclr_init_ppo(F,B,O,M) \
385 	Infoclr_init_data(F,B,O,M)
386 
387 #define Infoclr_init_cco(F,B,O,M) \
388 	Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
389 
390 #define Infoclr_init_ppn(F,B,O,M) \
391 	Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
392 
393 #define Infoclr_init_ccn(F,B,O,M) \
394 	Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
395 
396 
397 /* Set the current infofnt */
398 #define Infofnt_set(I) \
399 	(Infofnt = (I))
400 
401 
402 
403 /**** Generic Globals ****/
404 
405 
406 /*
407  * The "default" values
408  */
409 static metadpy metadpy_default;
410 
411 
412 /*
413  * The "current" variables
414  */
415 static metadpy *Metadpy = &metadpy_default;
416 static infowin *Infowin = (infowin*)(NULL);
417 static infoclr *Infoclr = (infoclr*)(NULL);
418 static infofnt *Infofnt = (infofnt*)(NULL);
419 
420 
421 
422 /**** Generic code ****/
423 
424 
425 /*
426  * Init the current metadpy, with various initialization stuff.
427  *
428  * Inputs:
429  *	dpy:  The Display* to use (if NULL, create it)
430  *	name: The name of the Display (if NULL, the current)
431  *
432  * Notes:
433  *	If 'name' is NULL, but 'dpy' is set, extract name from dpy
434  *	If 'dpy' is NULL, then Create the named Display
435  *	If 'name' is NULL, and so is 'dpy', use current Display
436  *
437  * Return -1 if no Display given, and none can be opened.
438  */
Metadpy_init_2(Display * dpy,cptr name)439 static errr Metadpy_init_2(Display *dpy, cptr name)
440 {
441 	metadpy *m = Metadpy;
442 
443 	/*** Open the display if needed ***/
444 
445 	/* If no Display given, attempt to Create one */
446 	if (!dpy)
447 	{
448 		/* Attempt to open the display */
449 		dpy = XOpenDisplay(name);
450 
451 		/* Failure */
452 		if (!dpy) return (-1);
453 
454 		/* We will have to nuke it when done */
455 		m->nuke = 1;
456 	}
457 
458 	/* Since the Display was given, use it */
459 	else
460 	{
461 		/* We will not have to nuke it when done */
462 		m->nuke = 0;
463 	}
464 
465 
466 	/*** Save some information ***/
467 
468 	/* Save the Display itself */
469 	m->dpy = dpy;
470 
471 	/* Get the Screen and Virtual Root Window */
472 	m->screen = DefaultScreenOfDisplay(dpy);
473 	m->root = RootWindowOfScreen(m->screen);
474 
475 	/* Get the default colormap */
476 	m->cmap = DefaultColormapOfScreen(m->screen);
477 
478 	/* Extract the true name of the display */
479 	m->name = DisplayString(dpy);
480 
481 	/* Extract the fd */
482 	m->fd = ConnectionNumber(Metadpy->dpy);
483 
484 	/* Save the Size and Depth of the screen */
485 	m->width = WidthOfScreen(m->screen);
486 	m->height = HeightOfScreen(m->screen);
487 	m->depth = DefaultDepthOfScreen(m->screen);
488 
489 	/* Save the Standard Colors */
490 	m->black = BlackPixelOfScreen(m->screen);
491 	m->white = WhitePixelOfScreen(m->screen);
492 
493 	/*** Make some clever Guesses ***/
494 
495 	/* Guess at the desired 'fg' and 'bg' Pixell's */
496 	m->bg = m->black;
497 	m->fg = m->white;
498 
499 	/* Calculate the Maximum allowed Pixel value.  */
500 	m->zg = ((Pixell)1 << m->depth) - 1;
501 
502 	/* Save various default Flag Settings */
503 	m->color = ((m->depth > 1) ? 1 : 0);
504 	m->mono = ((m->color) ? 0 : 1);
505 
506 	/* Return "success" */
507 	return (0);
508 }
509 
510 
511 #ifndef IGNORE_UNUSED_FUNCTIONS
512 
513 /*
514  * Nuke the current metadpy
515  */
Metadpy_nuke(void)516 static errr Metadpy_nuke(void)
517 {
518 	metadpy *m = Metadpy;
519 
520 
521 	/* If required, Free the Display */
522 	if (m->nuke)
523 	{
524 		/* Close the Display */
525 		XCloseDisplay(m->dpy);
526 
527 		/* Forget the Display */
528 		m->dpy = (Display*)(NULL);
529 
530 		/* Do not nuke it again */
531 		m->nuke = 0;
532 	}
533 
534 	/* Return Success */
535 	return (0);
536 }
537 
538 #endif /* IGNORE_UNUSED_FUNCTIONS */
539 
540 
541 /*
542  * General Flush/ Sync/ Discard routine
543  */
Metadpy_update(int flush,int sync,int discard)544 static errr Metadpy_update(int flush, int sync, int discard)
545 {
546 	/* Flush if desired */
547 	if (flush) XFlush(Metadpy->dpy);
548 
549 	/* Sync if desired, using 'discard' */
550 	if (sync) XSync(Metadpy->dpy, discard);
551 
552 	/* Success */
553 	return (0);
554 }
555 
556 
557 /*
558  * Make a simple beep
559  */
Metadpy_do_beep(void)560 static errr Metadpy_do_beep(void)
561 {
562 	/* Make a simple beep */
563 	XBell(Metadpy->dpy, 100);
564 
565 	return (0);
566 }
567 
568 
569 
570 /*
571  * Set the name (in the title bar) of Infowin
572  */
Infowin_set_name(cptr name)573 static errr Infowin_set_name(cptr name)
574 {
575 	Status st;
576 	XTextProperty tp;
577 	char buf[128];
578 	char *bp = buf;
579 	strnfmt(buf, sizeof(buf), "%s", name);
580 	st = XStringListToTextProperty(&bp, 1, &tp);
581 	if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
582 	return (0);
583 }
584 
585 
586 #ifndef IGNORE_UNUSED_FUNCTIONS
587 
588 /*
589  * Set the icon name of Infowin
590  */
Infowin_set_icon_name(cptr name)591 static errr Infowin_set_icon_name(cptr name)
592 {
593 	Status st;
594 	XTextProperty tp;
595 	char buf[128];
596 	char *bp = buf;
597 	strnfmt(buf, sizeof(buf), "%s", name);
598 	st = XStringListToTextProperty(&bp, 1, &tp);
599 	if (st) XSetWMIconName(Metadpy->dpy, Infowin->win, &tp);
600 	return (0);
601 }
602 
603 
604 /*
605  * Nuke Infowin
606  */
Infowin_nuke(void)607 static errr Infowin_nuke(void)
608 {
609 	infowin *iwin = Infowin;
610 
611 	/* Nuke if requested */
612 	if (iwin->nuke)
613 	{
614 		/* Destory the old window */
615 		XDestroyWindow(Metadpy->dpy, iwin->win);
616 	}
617 
618 	/* Success */
619 	return (0);
620 }
621 
622 #endif /* IGNORE_UNUSED_FUNCTIONS */
623 
624 
625 /*
626  * Prepare a new 'infowin'.
627  */
Infowin_prepare(Window xid)628 static errr Infowin_prepare(Window xid)
629 {
630 	infowin *iwin = Infowin;
631 
632 	Window tmp_win;
633 	XWindowAttributes xwa;
634 	int x, y;
635 	unsigned int w, h, b, d;
636 
637 	/* Assign stuff */
638 	iwin->win = xid;
639 
640 	/* Check For Error XXX Extract some ACTUAL data from 'xid' */
641 	XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
642 
643 	/* Apply the above info */
644 	iwin->x = x;
645 	iwin->y = y;
646 	iwin->w = w;
647 	iwin->h = h;
648 	iwin->b = b;
649 
650 	/* Check Error XXX Extract some more ACTUAL data */
651 	XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
652 
653 	/* Apply the above info */
654 	iwin->mask = xwa.your_event_mask;
655 	iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
656 
657 	/* Success */
658 	return (0);
659 }
660 
661 
662 #ifndef IGNORE_UNUSED_FUNCTIONS
663 
664 /*
665  * Initialize a new 'infowin'.
666  */
Infowin_init_real(Window xid)667 static errr Infowin_init_real(Window xid)
668 {
669 	/* Wipe it clean */
670 	(void)WIPE(Infowin, infowin);
671 
672 	/* Start out non-nukable */
673 	Infowin->nuke = 0;
674 
675 	/* Attempt to Prepare ourself */
676 	return (Infowin_prepare(xid));
677 }
678 
679 #endif /* IGNORE_UNUSED_FUNCTIONS */
680 
681 
682 /*
683  * Init an infowin by giving some data.
684  *
685  * Inputs:
686  *	dad: The Window that should own this Window (if any)
687  *	x,y: The position of this Window
688  *	w,h: The size of this Window
689  *	b,d: The border width and pixel depth
690  *
691  * Notes:
692  *	If 'dad == None' assume 'dad == root'
693  */
Infowin_init_data(Window dad,int x,int y,int w,int h,int b,Pixell fg,Pixell bg)694 static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
695                               int b, Pixell fg, Pixell bg)
696 {
697 	Window xid;
698 
699 	/* Wipe it clean */
700 	(void)WIPE(Infowin, infowin);
701 
702 
703 	/*** Error Check XXX ***/
704 
705 
706 	/*** Create the Window 'xid' from data ***/
707 
708 	/* What happened here?  XXX XXX XXX */
709 
710 	/* If no parent given, depend on root */
711 	if (dad == None)
712 
713 /* #ifdef USE_GRAPHICS
714 
715 		xid = XCreateWindow(Metadpy->dpy, Metadpy->root, x, y, w, h, b, 8, InputOutput, CopyFromParent, 0, 0);
716 
717 	else
718 */
719 
720 /* #else */
721 
722 		dad = Metadpy->root;
723 
724 /* #endif */
725 
726 	/* Create the Window XXX Error Check */
727 	xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
728 
729 	/* Start out selecting No events */
730 	XSelectInput(Metadpy->dpy, xid, 0L);
731 
732 
733 	/*** Prepare the new infowin ***/
734 
735 	/* Mark it as nukable */
736 	Infowin->nuke = 1;
737 
738 	/* Attempt to Initialize the infowin */
739 	return (Infowin_prepare(xid));
740 }
741 
742 
743 
744 /*
745  * Modify the event mask of an Infowin
746  */
Infowin_set_mask(long mask)747 static errr Infowin_set_mask(long mask)
748 {
749 	/* Save the new setting */
750 	Infowin->mask = mask;
751 
752 	/* Execute the Mapping */
753 	XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
754 
755 	/* Success */
756 	return (0);
757 }
758 
759 
760 /*
761  * Request that Infowin be mapped
762  */
Infowin_map(void)763 static errr Infowin_map(void)
764 {
765 	/* Execute the Mapping */
766 	XMapWindow(Metadpy->dpy, Infowin->win);
767 
768 	/* Success */
769 	return (0);
770 }
771 
772 
773 #ifndef IGNORE_UNUSED_FUNCTIONS
774 
775 /*
776  * Request that Infowin be unmapped
777  */
Infowin_unmap(void)778 static errr Infowin_unmap(void)
779 {
780 	/* Execute the Un-Mapping */
781 	XUnmapWindow(Metadpy->dpy, Infowin->win);
782 
783 	/* Success */
784 	return (0);
785 }
786 
787 #endif /* IGNORE_UNUSED_FUNCTIONS */
788 
789 
790 /*
791  * Request that Infowin be raised
792  */
Infowin_raise(void)793 static errr Infowin_raise(void)
794 {
795 	/* Raise towards visibility */
796 	XRaiseWindow(Metadpy->dpy, Infowin->win);
797 
798 	/* Success */
799 	return (0);
800 }
801 
802 
803 #ifndef IGNORE_UNUSED_FUNCTIONS
804 
805 /*
806  * Request that Infowin be lowered
807  */
Infowin_lower(void)808 static errr Infowin_lower(void)
809 {
810 	/* Lower towards invisibility */
811 	XLowerWindow(Metadpy->dpy, Infowin->win);
812 
813 	/* Success */
814 	return (0);
815 }
816 
817 #endif /* IGNORE_UNUSED_FUNCTIONS */
818 
819 
820 /*
821  * Request that Infowin be moved to a new location
822  */
Infowin_impell(int x,int y)823 static errr Infowin_impell(int x, int y)
824 {
825 	/* Execute the request */
826 	XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
827 
828 	/* Success */
829 	return (0);
830 }
831 
832 
833 /*
834  * Resize an infowin
835  */
Infowin_resize(int w,int h)836 static errr Infowin_resize(int w, int h)
837 {
838 	/* Execute the request */
839 	XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
840 
841 	/* Success */
842 	return (0);
843 }
844 
845 
846 #ifndef IGNORE_UNUSED_FUNCTIONS
847 
848 /*
849  * Move and Resize an infowin
850  */
Infowin_locate(int x,int y,int w,int h)851 static errr Infowin_locate(int x, int y, int w, int h)
852 {
853 	/* Execute the request */
854 	XMoveResizeWindow(Metadpy->dpy, Infowin->win, x, y, w, h);
855 
856 	/* Success */
857 	return (0);
858 }
859 
860 
861 /*
862  * Visually clear Infowin
863  */
Infowin_wipe(void)864 static errr Infowin_wipe(void)
865 {
866 	/* Execute the request */
867 	XClearWindow(Metadpy->dpy, Infowin->win);
868 
869 	/* Success */
870 	return (0);
871 }
872 
873 
874 /*
875  * Visually Paint Infowin with the current color
876  */
Infowin_fill(void)877 static errr Infowin_fill(void)
878 {
879 	/* Execute the request */
880 	XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc,
881 	               0, 0, Infowin->w, Infowin->h);
882 
883 	/* Success */
884 	return (0);
885 }
886 
887 #endif /* IGNORE_UNUSED_FUNCTIONS */
888 
889 
890 /*
891  * A NULL terminated pair list of legal "operation names"
892  *
893  * Pairs of values, first is texttual name, second is the string
894  * holding the decimal value that the operation corresponds to.
895  */
896 static cptr opcode_pairs[] =
897 {
898 	"cpy", "3",
899 	"xor", "6",
900 	"and", "1",
901 	"ior", "7",
902 	"nor", "8",
903 	"inv", "10",
904 	"clr", "0",
905 	"set", "15",
906 
907 	"src", "3",
908 	"dst", "5",
909 
910 	"+andReverse", "2",
911 	"+andInverted", "4",
912 	"+noop", "5",
913 	"+equiv", "9",
914 	"+orReverse", "11",
915 	"+copyInverted", "12",
916 	"+orInverted", "13",
917 	"+nand", "14",
918 	NULL
919 };
920 
921 
922 /*
923  * Parse a word into an operation "code"
924  *
925  * Inputs:
926  *	str: A string, hopefully representing an Operation
927  *
928  * Output:
929  *	0-15: if 'str' is a valid Operation
930  *	-1:   if 'str' could not be parsed
931  */
Infoclr_Opcode(cptr str)932 static int Infoclr_Opcode(cptr str)
933 {
934 	register int i;
935 
936 	/* Scan through all legal operation names */
937 	for (i = 0; opcode_pairs[i*2]; ++i)
938 	{
939 		/* Is this the right oprname? */
940 		if (streq(opcode_pairs[i*2], str))
941 		{
942 			/* Convert the second element in the pair into a Code */
943 			return (atoi(opcode_pairs[i*2+1]));
944 		}
945 	}
946 
947 	/* The code was not found, return -1 */
948 	return (-1);
949 }
950 
951 
952 #ifndef IGNORE_UNUSED_FUNCTIONS
953 
954 /*
955  * Request a Pixell by name.  Note: uses 'Metadpy'.
956  *
957  * Inputs:
958  *      name: The name of the color to try to load (see below)
959  *
960  * Output:
961  *	The Pixell value that metched the given name
962  *	'Metadpy->fg' if the name was unparseable
963  *
964  * Valid forms for 'name':
965  *	'fg', 'bg', 'zg', '<name>' and '#<code>'
966  */
Infoclr_Pixell(cptr name)967 static Pixell Infoclr_Pixell(cptr name)
968 {
969 	XColor scrn;
970 
971 	/* Attempt to Parse the name */
972 	if (name && name[0])
973 	{
974 		/* The 'bg' color is available */
975 		if (streq(name, "bg")) return (Metadpy->bg);
976 
977 		/* The 'fg' color is available */
978 		if (streq(name, "fg")) return (Metadpy->fg);
979 
980 		/* The 'zg' color is available */
981 		if (streq(name, "zg")) return (Metadpy->zg);
982 
983 		/* The 'white' color is available */
984 		if (streq(name, "white")) return (Metadpy->white);
985 
986 		/* The 'black' color is available */
987 		if (streq(name, "black")) return (Metadpy->black);
988 
989 		/* Attempt to parse 'name' into 'scrn' */
990 		if (!(XParseColor(Metadpy->dpy, Metadpy->cmap, name, &scrn)))
991 		{
992 			plog_fmt("Warning: Couldn't parse color '%s'\n", name);
993 		}
994 
995 		/* Attempt to Allocate the Parsed color */
996 		if (!(XAllocColor(Metadpy->dpy, Metadpy->cmap, &scrn)))
997 		{
998 			plog_fmt("Warning: Couldn't allocate color '%s'\n", name);
999 		}
1000 
1001 		/* The Pixel was Allocated correctly */
1002 		else return (scrn.pixel);
1003 	}
1004 
1005 	/* Warn about the Default being Used */
1006 	plog_fmt("Warning: Using 'fg' for unknown color '%s'\n", name);
1007 
1008 	/* Default to the 'Foreground' color */
1009 	return (Metadpy->fg);
1010 }
1011 
1012 
1013 /*
1014  * Initialize a new 'infoclr' with a real GC.
1015  */
Infoclr_init_1(GC gc)1016 static errr Infoclr_init_1(GC gc)
1017 {
1018 	infoclr *iclr = Infoclr;
1019 
1020 	/* Wipe the iclr clean */
1021 	(void)WIPE(iclr, infoclr);
1022 
1023 	/* Assign the GC */
1024 	iclr->gc = gc;
1025 
1026 	/* Success */
1027 	return (0);
1028 }
1029 
1030 
1031 /*
1032  * Nuke an old 'infoclr'.
1033  */
Infoclr_nuke(void)1034 static errr Infoclr_nuke(void)
1035 {
1036 	infoclr *iclr = Infoclr;
1037 
1038 	/* Deal with 'GC' */
1039 	if (iclr->nuke)
1040 	{
1041 		/* Free the GC */
1042 		XFreeGC(Metadpy->dpy, iclr->gc);
1043 	}
1044 
1045 	/* Forget the current */
1046 	Infoclr = (infoclr*)(NULL);
1047 
1048 	/* Success */
1049 	return (0);
1050 }
1051 
1052 #endif /* IGNORE_UNUSED_FUNCTIONS */
1053 
1054 
1055 /*
1056  * Initialize an infoclr with some data
1057  *
1058  * Inputs:
1059  *	fg:   The Pixell for the requested Foreground (see above)
1060  *	bg:   The Pixell for the requested Background (see above)
1061  *	op:   The Opcode for the requested Operation (see above)
1062  *	stip: The stipple mode
1063  */
Infoclr_init_data(Pixell fg,Pixell bg,int op,int stip)1064 static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
1065 {
1066 	infoclr *iclr = Infoclr;
1067 
1068 	GC gc;
1069 	XGCValues gcv;
1070 	unsigned long gc_mask;
1071 
1072 
1073 
1074 	/*** Simple error checking of opr and clr ***/
1075 
1076 	/* Check the 'Pixells' for realism */
1077 	if (bg > Metadpy->zg) return (-1);
1078 	if (fg > Metadpy->zg) return (-1);
1079 
1080 	/* Check the data for trueness */
1081 	if ((op < 0) || (op > 15)) return (-1);
1082 
1083 
1084 	/*** Create the requested 'GC' ***/
1085 
1086 	/* Assign the proper GC function */
1087 	gcv.function = op;
1088 
1089 	/* Assign the proper GC background */
1090 	gcv.background = bg;
1091 
1092 	/* Assign the proper GC foreground */
1093 	gcv.foreground = fg;
1094 
1095 	/* Hack -- Handle XOR (xor is code 6) by hacking bg and fg */
1096 	if (op == 6) gcv.background = 0;
1097 	if (op == 6) gcv.foreground = (bg ^ fg);
1098 
1099 	/* Assign the proper GC Fill Style */
1100 	gcv.fill_style = (stip ? FillStippled : FillSolid);
1101 
1102 	/* Turn off 'Give exposure events for pixmap copying' */
1103 	gcv.graphics_exposures = False;
1104 
1105 	/* Set up the GC mask */
1106 	gc_mask = (GCFunction | GCBackground | GCForeground |
1107 	           GCFillStyle | GCGraphicsExposures);
1108 
1109 	/* Create the GC detailed above */
1110 	gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
1111 
1112 
1113 	/*** Initialize ***/
1114 
1115 	/* Wipe the iclr clean */
1116 	(void)WIPE(iclr, infoclr);
1117 
1118 	/* Assign the GC */
1119 	iclr->gc = gc;
1120 
1121 	/* Nuke it when done */
1122 	iclr->nuke = 1;
1123 
1124 	/* Assign the parms */
1125 	iclr->fg = fg;
1126 	iclr->bg = bg;
1127 	iclr->code = op;
1128 	iclr->stip = stip ? 1 : 0;
1129 
1130 	/* Success */
1131 	return (0);
1132 }
1133 
1134 
1135 
1136 /*
1137  * Change the 'fg' for an infoclr
1138  *
1139  * Inputs:
1140  *	fg:   The Pixell for the requested Foreground (see above)
1141  */
Infoclr_change_fg(Pixell fg)1142 static errr Infoclr_change_fg(Pixell fg)
1143 {
1144 	infoclr *iclr = Infoclr;
1145 
1146 
1147 	/*** Simple error checking of opr and clr ***/
1148 
1149 	/* Check the 'Pixells' for realism */
1150 	if (fg > Metadpy->zg) return (-1);
1151 
1152 
1153 	/*** Change ***/
1154 
1155 	/* Change */
1156 	XSetForeground(Metadpy->dpy, iclr->gc, fg);
1157 
1158 	/* Success */
1159 	return (0);
1160 }
1161 
1162 
1163 
1164 #ifndef IGNORE_UNUSED_FUNCTIONS
1165 
1166 /*
1167  * Nuke an old 'infofnt'.
1168  */
Infofnt_nuke(void)1169 static errr Infofnt_nuke(void)
1170 {
1171 	infofnt *ifnt = Infofnt;
1172 
1173 	/* Deal with 'name' */
1174 	if (ifnt->name)
1175 	{
1176 		/* Free the name */
1177 		string_free(ifnt->name);
1178 	}
1179 
1180 	/* Nuke info if needed */
1181 	if (ifnt->nuke)
1182 	{
1183 		/* Free the font */
1184 		XFreeFont(Metadpy->dpy, ifnt->info);
1185 	}
1186 
1187 	/* Success */
1188 	return (0);
1189 }
1190 
1191 #endif /* IGNORE_UNUSED_FUNCTIONS */
1192 
1193 
1194 /*
1195  * Prepare a new 'infofnt'
1196  */
Infofnt_prepare(XFontStruct * info)1197 static errr Infofnt_prepare(XFontStruct *info)
1198 {
1199 	infofnt *ifnt = Infofnt;
1200 
1201 	XCharStruct *cs;
1202 
1203 	/* Assign the struct */
1204 	ifnt->info = info;
1205 
1206 	/* Jump into the max bounds thing */
1207 	cs = &(info->max_bounds);
1208 
1209 	/* Extract default sizing info */
1210 	ifnt->asc = info->ascent;
1211 	ifnt->hgt = info->ascent + info->descent;
1212 	ifnt->wid = cs->width;
1213 
1214 #ifdef OBSOLETE_SIZING_METHOD
1215 	/* Extract default sizing info */
1216 	ifnt->asc = cs->ascent;
1217 	ifnt->hgt = (cs->ascent + cs->descent);
1218 	ifnt->wid = cs->width;
1219 #endif
1220 
1221 	if (use_bigtile)
1222 		ifnt->twid = 2 * cs->width;
1223 	else
1224 		ifnt->twid = cs->width;
1225 
1226 	/* Success */
1227 	return (0);
1228 }
1229 
1230 
1231 #ifndef IGNORE_UNUSED_FUNCTIONS
1232 
1233 /*
1234  * Initialize a new 'infofnt'.
1235  */
Infofnt_init_real(XFontStruct * info)1236 static errr Infofnt_init_real(XFontStruct *info)
1237 {
1238 	/* Wipe the thing */
1239 	(void)WIPE(Infofnt, infofnt);
1240 
1241 	/* No nuking */
1242 	Infofnt->nuke = 0;
1243 
1244 	/* Attempt to prepare it */
1245 	return (Infofnt_prepare(info));
1246 }
1247 
1248 #endif /* IGNORE_UNUSED_FUNCTIONS */
1249 
1250 
1251 /*
1252  * Init an infofnt by its Name
1253  *
1254  * Inputs:
1255  *	name: The name of the requested Font
1256  */
Infofnt_init_data(cptr name)1257 static errr Infofnt_init_data(cptr name)
1258 {
1259 	XFontStruct *info;
1260 
1261 
1262 	/*** Load the info Fresh, using the name ***/
1263 
1264 	/* If the name is not given, report an error */
1265 	if (!name)
1266 	{
1267 		plog_fmt("Missing font! %s", name);
1268 
1269 		return (-1);
1270 	}
1271 
1272 	/* Attempt to load the font */
1273 	info = XLoadQueryFont(Metadpy->dpy, name);
1274 
1275 	/* The load failed */
1276 	if (!info)
1277 	{
1278 		plog_fmt("Failed to find font:\"%s\"", name);
1279 
1280 		return (-1);
1281 	}
1282 
1283 	/*** Init the font ***/
1284 
1285 	/* Wipe the thing */
1286 	(void)WIPE(Infofnt, infofnt);
1287 
1288 	/* Attempt to prepare it */
1289 	if (Infofnt_prepare(info))
1290 	{
1291 		/* Free the font */
1292 		XFreeFont(Metadpy->dpy, info);
1293 
1294 		/* Fail */
1295 		plog_fmt("Failed to prepare font:\"%s\"", name);
1296 
1297 		return (-1);
1298 	}
1299 
1300 	/* Save a copy of the font name */
1301 	Infofnt->name = string_make(name);
1302 
1303 	/* Mark it as nukable */
1304 	Infofnt->nuke = 1;
1305 
1306 	/* Success */
1307 	return (0);
1308 }
1309 
1310 
1311 /*
1312  * Find the square a particular pixel is part of.
1313  */
pixel_to_square(int * x,int * y,int ox,int oy)1314 static void pixel_to_square(int *x, int *y, int ox, int oy)
1315 {
1316 	(*x) = (ox - Infowin->ox) / Infofnt->wid;
1317 	(*y) = (oy - Infowin->oy) / Infofnt->hgt;
1318 
1319 	if ((use_bigtile) && ((*y) >= Term->scr->big_y1)
1320 		&& ((*y) <= Term->scr->big_y2)
1321 		&& ((*x) >= Term->scr->big_x1))
1322 	{
1323 		(*x) -= ((*x) - Term->scr->big_x1 + 1) / 2;
1324 	}
1325 }
1326 
1327 /*
1328  * Find the pixel at the top-left corner of a square.
1329  */
square_to_pixel(int * x,int * y,int ox,int oy)1330 static void square_to_pixel(int *x, int *y, int ox, int oy)
1331 {
1332 	(*y) = oy * Infofnt->hgt + Infowin->oy;
1333 
1334 	if ((use_bigtile) && (oy >= Term->scr->big_y1)
1335 			&& (oy <= Term->scr->big_y2)
1336 			&& (ox > Term->scr->big_x1))
1337 	{
1338 		(*x) = ox * Infofnt->twid + Infowin->ox -
1339 				Term->scr->big_x1 * Infofnt->wid;
1340 	}
1341 	else
1342 	{
1343 		(*x) = ox * Infofnt->wid + Infowin->ox;
1344 	}
1345 }
1346 
1347 
1348 
1349 /*
1350  * Painting where text would be
1351  */
Infofnt_text_non(int x,int y,int len)1352 static errr Infofnt_text_non(int x, int y, int len)
1353 {
1354 	int x1, y1, x2, y2;
1355 
1356 	/*** Find the dimensions ***/
1357 	square_to_pixel(&x1, &y1, x, y);
1358 	square_to_pixel(&x2, &y2, x + len, y);
1359 
1360 	/*** Actually 'paint' the area ***/
1361 
1362 	/* Just do a Fill Rectangle */
1363 	XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc,
1364 					x1, y1,
1365 					x2 - x1, Infofnt->hgt);
1366 
1367 	/* Success */
1368 	return (0);
1369 }
1370 
1371 
1372 /*
1373  * Standard Text
1374  */
Infofnt_text_std(int cx,int cy,cptr str,int len)1375 static errr Infofnt_text_std(int cx, int cy, cptr str, int len)
1376 {
1377 	int i;
1378 
1379 	int x, y;
1380 
1381 
1382 	/*** Do a brief info analysis ***/
1383 
1384 	/* Do nothing if the string is null */
1385 	if (!str || !*str) return (-1);
1386 
1387 	/* Get the length of the string */
1388 	if (len < 0) len = strlen(str);
1389 
1390 	/*** Decide where to place the string, vertically ***/
1391 
1392 	square_to_pixel(&x, &y, cx, cy);
1393 
1394 	/* Ignore Vertical Justifications */
1395 	y += Infofnt->asc;
1396 
1397 
1398 	/*** Actually draw 'str' onto the infowin ***/
1399 
1400 	/* Be sure the correct font is ready */
1401 	XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1402 
1403 
1404 	/*** Handle the fake mono we can enforce on fonts ***/
1405 
1406 	/* Monotize the font if required */
1407 	if (Infofnt->mono || is_bigtiled(cx + len - 1, cy))
1408 	{
1409 		/* Horizontal Justification */
1410 		x += Infofnt->off;
1411 
1412 		/* Do each character */
1413 		for (i = 0; i < len; ++i)
1414 		{
1415 			if (is_bigtiled(cx + i, cy))
1416 			{
1417 				/* Note that the Infoclr is set up to contain the Infofnt */
1418 				XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1419 								x, y, str + i, 1);
1420 				x += Infofnt->twid;
1421 			}
1422 			else
1423 			{
1424 				/* Note that the Infoclr is set up to contain the Infofnt */
1425 				XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1426 								x, y, str + i, 1);
1427 				x += Infofnt->wid;
1428 			}
1429 		}
1430 	}
1431 
1432 	/* Assume monoospaced font */
1433 	else
1434 	{
1435 		/* Note that the Infoclr is set up to contain the Infofnt */
1436 		XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1437 		                 x, y, str, len);
1438 	}
1439 
1440 
1441 	/* Success */
1442 	return (0);
1443 }
1444 
1445 
1446 /*
1447  * Hack -- cursor color
1448  */
1449 static infoclr *xor;
1450 
1451 /*
1452  * Actual color table
1453  */
1454 static infoclr *clr[256];
1455 
1456 /*
1457  * Color info (unused, red, green, blue).
1458  */
1459 static byte color_table[256][4];
1460 
1461 /*
1462  * Forward declare
1463  */
1464 typedef struct term_data term_data;
1465 
1466 /*
1467  * A structure for each "term"
1468  */
1469 struct term_data
1470 {
1471 	term t;
1472 
1473 	infofnt *fnt;
1474 
1475 	infowin *win;
1476 
1477 #ifdef USE_GRAPHICS
1478 
1479 	XImage *tiles;
1480 	XImage *b_tiles;
1481 
1482 	/* Temporary storage for overlaying tiles. */
1483 	XImage *TmpImage;
1484 
1485 #endif /* USE_GRAPHICS */
1486 
1487 };
1488 
1489 
1490 /*
1491  * The number of term data structures
1492  */
1493 #define MAX_TERM_DATA 8
1494 
1495 /*
1496  * The array of term data structures
1497  */
1498 static term_data data[MAX_TERM_DATA];
1499 
1500 /* Use short names for the most commonly used elements of various structures. */
1501 #define DPY (Metadpy->dpy)
1502 #define WIN (Infowin->win)
1503 
1504 
1505 /* Describe a set of co-ordinates. */
1506 typedef struct co_ord co_ord;
1507 struct co_ord
1508 {
1509 	int x;
1510 	int y;
1511 };
1512 
1513 
1514 /*
1515  * A special structure to store information about the text currently
1516  * selected.
1517  */
1518 typedef struct x11_selection_type x11_selection_type;
1519 struct x11_selection_type
1520 {
1521 	bool select; /* The selection is currently in use. */
1522 	bool drawn; /* The selection is currently displayed. */
1523 	term *t; /* The window where the selection is found. */
1524 	co_ord init; /* The starting co-ordinates. */
1525 	co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1526 	co_ord old; /* The previous end co-ordinates. */
1527 	Time time; /* The time at which the selection was finalised. */
1528 };
1529 
1530 static x11_selection_type x11_selection[1];
1531 
1532 
1533 /*
1534  * Process a keypress event
1535  *
1536  * Also appears in "main-xaw.c".
1537  */
react_keypress(XKeyEvent * ev)1538 static void react_keypress(XKeyEvent *ev)
1539 {
1540 	int i, n, mc, ms, mo, mx;
1541 
1542 	uint ks1;
1543 
1544 	KeySym ks;
1545 
1546 	char buf[128];
1547 	char msg[128];
1548 
1549 
1550 	/* Check for "normal" keypresses */
1551 	n = XLookupString(ev, buf, 125, &ks, NULL);
1552 
1553 	/* Terminate */
1554 	buf[n] = '\0';
1555 
1556 
1557 	/* Hack -- Ignore "modifier keys" */
1558 	if (IsModifierKey(ks)) return;
1559 
1560 
1561 	/* Hack -- convert into an unsigned int */
1562 	ks1 = (uint)(ks);
1563 
1564 	/* Extract four "modifier flags" */
1565 	mc = (ev->state & ControlMask) ? TRUE : FALSE;
1566 	ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1567 	mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1568 	mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1569 
1570 
1571 	/* Normal keys with no modifiers */
1572 	if (n && !mo && !mx && !IsSpecialKey(ks))
1573 	{
1574 		/* Enqueue the normal key(s) */
1575 		for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1576 
1577 		/* All done */
1578 		return;
1579 	}
1580 
1581 
1582 	/* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1583 	switch (ks1)
1584 	{
1585 		case XK_Escape:
1586 		{
1587 			Term_keypress(ESCAPE);
1588 			return;
1589 		}
1590 
1591 		case XK_Return:
1592 		{
1593 			Term_keypress('\r');
1594 			return;
1595 		}
1596 
1597 		case XK_Tab:
1598 		{
1599 			Term_keypress('\t');
1600 			return;
1601 		}
1602 
1603 		case XK_Delete:
1604 		case XK_BackSpace:
1605 		{
1606 			Term_keypress('\010');
1607 			return;
1608 		}
1609 	}
1610 
1611 
1612 	/* Hack -- Use the KeySym */
1613 	if (ks)
1614 	{
1615 		strnfmt(msg, sizeof(msg), "%c%s%s%s%s_%lX%c", 31,
1616 		        mc ? "N" : "", ms ? "S" : "",
1617 		        mo ? "O" : "", mx ? "M" : "",
1618 		        (unsigned long)(ks), 13);
1619 	}
1620 
1621 	/* Hack -- Use the Keycode */
1622 	else
1623 	{
1624 		strnfmt(msg, sizeof(msg), "%c%s%s%s%sK_%X%c", 31,
1625 		        mc ? "N" : "", ms ? "S" : "",
1626 		        mo ? "O" : "", mx ? "M" : "",
1627 		        ev->keycode, 13);
1628 	}
1629 
1630 	/* Enqueue the "macro trigger" string */
1631 	for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1632 
1633 
1634 	/* Hack -- auto-define macros as needed */
1635 	if (n && (macro_find_exact(msg) < 0))
1636 	{
1637 		/* Create a macro */
1638 		macro_add(msg, buf);
1639 	}
1640 }
1641 
1642 
1643 /*
1644  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
1645  */
sort_co_ord(co_ord * min,co_ord * max,const co_ord * b,const co_ord * a)1646 static void sort_co_ord(co_ord *min, co_ord *max,
1647                         const co_ord *b, const co_ord *a)
1648 {
1649 	min->x = MIN(a->x, b->x);
1650 	min->y = MIN(a->y, b->y);
1651 	max->x = MAX(a->x, b->x);
1652 	max->y = MAX(a->y, b->y);
1653 
1654 	/* Prevent bigtile wierdness */
1655 	if (is_bigtiled(min->x, min->y) != is_bigtiled(max->x, max->y))
1656 	{
1657 		if (min->y < Term->scr->big_y1) min->y = Term->scr->big_y1;
1658 		if (max->y > Term->scr->big_y2) max->y = Term->scr->big_y2;
1659 	}
1660 }
1661 
1662 
1663 /*
1664  * Select an area by drawing a grey box around it.
1665  * Since we use XOR, we can undraw the box by using this
1666  * routine again. (The XOR method also works best for things like snow)
1667  */
mark_selection_mark(int x1,int y1,int x2,int y2)1668 static void mark_selection_mark(int x1, int y1, int x2, int y2)
1669 {
1670 	square_to_pixel(&x1, &y1, x1, y1);
1671 	if (is_bigtiled(x2, y2))
1672 	{
1673 		square_to_pixel(&x2, &y2, x2, y2);
1674 		XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc, x1, y1,
1675 			x2-x1+Infofnt->twid - 1, y2-y1+Infofnt->hgt - 1);
1676 	}
1677 	else
1678 	{
1679 		square_to_pixel(&x2, &y2, x2, y2);
1680 		XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc, x1, y1,
1681 			x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1682 	}
1683 }
1684 
1685 
1686 /*
1687  * Mark a selection by drawing boxes around it (for now).
1688  */
mark_selection(void)1689 static void mark_selection(void)
1690 {
1691 	co_ord min, max;
1692 	term *old = Term;
1693 	bool draw = x11_selection->select;
1694 	bool clear = x11_selection->drawn;
1695 
1696 	/* Open the correct term if necessary. */
1697 	if (x11_selection->t != old) Term_activate(x11_selection->t);
1698 
1699 	if (clear)
1700 	{
1701 		sort_co_ord(&min, &max, &x11_selection->init, &x11_selection->old);
1702 		mark_selection_mark(min.x, min.y, max.x, max.y);
1703 	}
1704 
1705 	if (draw)
1706 	{
1707 		sort_co_ord(&min, &max, &x11_selection->init, &x11_selection->cur);
1708 		mark_selection_mark(min.x, min.y, max.x, max.y);
1709 	}
1710 
1711 	/* Finish on the current term. */
1712 	if (x11_selection->t != old) Term_activate(old);
1713 
1714 	x11_selection->old.x = x11_selection->cur.x;
1715 	x11_selection->old.y = x11_selection->cur.y;
1716 	x11_selection->drawn = x11_selection->select;
1717 }
1718 
1719 
1720 /*
1721  * Forget a selection for one reason or another.
1722  */
copy_x11_release(void)1723 static void copy_x11_release(void)
1724 {
1725 	/* Deselect the current selection. */
1726 	x11_selection->select = FALSE;
1727 
1728 	/* Remove its graphical represesntation. */
1729 	mark_selection();
1730 }
1731 
1732 
1733 /*
1734  * Start to select some text on the screen.
1735  */
copy_x11_start(int x,int y)1736 static void copy_x11_start(int x, int y)
1737 {
1738 	if (x11_selection->select) copy_x11_release();
1739 
1740 	/* Remember where the selection started. */
1741 	x11_selection->t = Term;
1742 	x11_selection->init.x = x11_selection->cur.x = x11_selection->old.x = x;
1743 	x11_selection->init.y = x11_selection->cur.y = x11_selection->old.y = y;
1744 }
1745 
1746 
1747 /*
1748  * Respond to movement of the mouse when selecting text.
1749  */
copy_x11_cont(int x,int y,unsigned int buttons)1750 static void copy_x11_cont(int x, int y, unsigned int buttons)
1751 {
1752 	/* Use the nearest square within bounds if the mouse is outside. */
1753 	x = MIN(MAX(x, 0), Term->wid-1);
1754 	y = MIN(MAX(y, 0), Term->hgt-1);
1755 
1756 	/* The left mouse button isn't pressed. */
1757 	if (~buttons & Button1Mask) return;
1758 
1759 	/* Not a selection in this window. */
1760 	if (x11_selection->t != Term) return;
1761 
1762 	/* Not enough movement. */
1763 	if ((x == x11_selection->old.x) && (y == x11_selection->old.y) && x11_selection->select) return;
1764 
1765 	/* Something is being selected. */
1766 	x11_selection->select = TRUE;
1767 
1768 	/* Track the selection. */
1769 	x11_selection->cur.x = x;
1770 	x11_selection->cur.y = y;
1771 
1772 	/* Hack - display it inefficiently. */
1773 	mark_selection();
1774 }
1775 
1776 
1777 /*
1778  * Respond to release of the left mouse button by putting the selected text in
1779  * the primary buffer.
1780  */
copy_x11_end(const Time time)1781 static void copy_x11_end(const Time time)
1782 {
1783 	/* No selection. */
1784 	if (!x11_selection->select) return;
1785 
1786 	/* Not a selection in this window. */
1787 	if (x11_selection->t != Term) return;
1788 
1789 	/* Remember when the selection was finalised. */
1790 	x11_selection->time = time;
1791 
1792 	/* Acquire the primary selection. */
1793 	XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
1794 
1795 	if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
1796 	{
1797 		/* Failed to acquire the selection, so forget it. */
1798 		bell("Failed to acquire primary buffer.");
1799 		x11_selection->select = FALSE;
1800 		mark_selection();
1801 	}
1802 }
1803 
1804 
1805 /*
1806  * Send some text requested by another X client
1807  */
paste_x11_send(XSelectionRequestEvent * rq)1808 static void paste_x11_send(XSelectionRequestEvent *rq)
1809 {
1810 	XEvent event;
1811 	XSelectionEvent *ptr = &(event.xselection);
1812 
1813 	static Atom xa_targets = None;
1814 
1815 	if (xa_targets == None)
1816 		xa_targets = XInternAtom(DPY, "TARGETS", False);
1817 
1818 	/* Set the event parameters */
1819 	ptr->type = SelectionNotify;
1820 	ptr->property = rq->property;
1821 	ptr->display = rq->display;
1822 	ptr->requestor = rq->requestor;
1823 	ptr->selection = rq->selection;
1824 	ptr->target = rq->target;
1825 	ptr->time = rq->time;
1826 
1827 	if (rq->target == xa_targets)
1828 	{
1829 		Atom target_list[2];
1830 		target_list[0] = xa_targets;
1831 		target_list[1] = XA_STRING;
1832 
1833 		XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1834 		                (8 * sizeof(target_list[0])), PropModeReplace,
1835 		                (unsigned char *)target_list,
1836 		                (sizeof(target_list) / sizeof(target_list[0])));
1837 
1838 		event.xselection.property = rq->property;
1839 	}
1840 	else if (rq->target == XA_STRING)
1841 	{
1842 		/* Reply to a known target received recently with data */
1843 		byte buf[1024];
1844 		co_ord max, min;
1845 		int x, y, i;
1846 		byte a;
1847 		char c;
1848 
1849 		/* Work out which way around to paste */
1850 		sort_co_ord(&min, &max, &x11_selection->init, &x11_selection->cur);
1851 
1852 		/* Delete the old value of the property */
1853 		XDeleteProperty(DPY, rq->requestor, rq->property);
1854 
1855 		for (y = 0; y < Term->hgt; y++)
1856 		{
1857 			if (y < min.y) continue;
1858 			if (y > max.y) break;
1859 
1860 			for (x = i = 0; x < Term->wid; x++)
1861 			{
1862 				if (x < min.x) continue;
1863 				if (x > max.x) break;
1864 
1865 				/* Protect the buffer boundary */
1866 				if (i >= (int)(sizeof(buf) - 2)) break;
1867 
1868 				/* Find the character */
1869 				Term_what(x, y, &a, &c);
1870 
1871 				/* Add it */
1872 				buf[i++] = c;
1873 			}
1874 
1875 			/* Terminate all but the last line in an appropriate way */
1876 			if (y != max.y) buf[i++] = '\n';
1877 
1878 			/* Send the (non-empty) string */
1879 			XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
1880 			                PropModeAppend, buf, i);
1881 		}
1882 	}
1883 	else
1884 	{
1885 		/* Respond to all bad requests with property None */
1886 		ptr->property = None;
1887 	}
1888 
1889 	/* Send whatever event we're left with */
1890 	XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
1891 }
1892 
1893 
1894 /*
1895  * Handle various events conditional on presses of a mouse button.
1896  */
handle_button(Time time,int x,int y,int button,bool press)1897 static void handle_button(Time time, int x, int y, int button, bool press)
1898 {
1899 	/* The co-ordinates are only used in Angband format. */
1900 	pixel_to_square(&x, &y, x, y);
1901 
1902 	if (press && button == 1) copy_x11_start(x, y);
1903 	if (!press && button == 1) copy_x11_end(time);
1904 }
1905 
1906 
1907 /*
1908  * Delay resizing/redrawing windows so that don't waste cpu
1909  */
1910 static bool event_pending = FALSE;
1911 
scan_pending_windows(void)1912 static void scan_pending_windows(void)
1913 {
1914 	term_data *old_td = (term_data*)(Term->data);
1915 	term_data *td;
1916 
1917 	int i;
1918 
1919 	/* Unset flag */
1920 	event_pending = FALSE;
1921 
1922 	/* Scan the windows */
1923 	for (i = 0; i < MAX_TERM_DATA; i++)
1924 	{
1925 		td = &data[i];
1926 
1927 		/* Skip nonexistant terms */
1928 		if (!td->win) continue;
1929 
1930 		/* Hack -- activate the Term */
1931 		Term_activate(&td->t);
1932 
1933 		/* Need to resize? */
1934 		if (td->win->resize == TRUE)
1935 		{
1936 			int cols, rows, wid, hgt;
1937 
1938 			int ox = Infowin->ox;
1939 			int oy = Infowin->oy;
1940 
1941 			/* Unset flags */
1942 			td->win->resize = FALSE;
1943 			td->win->redraw = FALSE;
1944 
1945 			/* Hack -- activate the window */
1946 			Infowin_set(td->win);
1947 
1948 			/* Determine "proper" number of rows/cols */
1949 			cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
1950 			rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
1951 
1952 			/* Hack -- minimal size */
1953 			if (cols < 1) cols = 1;
1954 			if (rows < 1) rows = 1;
1955 
1956 			/* Hack the main window must be at least 80x24 */
1957 			if (i == 0)
1958 			{
1959 				if (cols < 80) cols = 80;
1960 				if (rows < 24) rows = 24;
1961 			}
1962 
1963 			/* Desired size of window */
1964 			wid = cols * td->fnt->wid + (ox + ox);
1965 			hgt = rows * td->fnt->hgt + (oy + oy);
1966 
1967 			/* Resize the windows if any "change" is needed */
1968 			if ((Infowin->w != wid) || (Infowin->h != hgt))
1969 			{
1970 				/* Resize window */
1971 				Infowin_set(td->win);
1972 				Infowin_resize(wid, hgt);
1973 			}
1974 
1975 			/* Resize the Term (if needed) */
1976 			(void)Term_resize(cols, rows);
1977 
1978 		}
1979 		else if (td->win->redraw == TRUE)
1980 		{
1981 			/* Unset flag */
1982 			td->win->redraw = FALSE;
1983 
1984 			Term_redraw();
1985 		}
1986 	}
1987 
1988 	/* Hack -- Activate the old term */
1989 	Term_activate(&old_td->t);
1990 
1991 	/* Hack -- Activate the proper window */
1992 	Infowin_set(old_td->win);
1993 }
1994 
1995 /*
1996  * Process events
1997  */
CheckEvent(bool wait)1998 static errr CheckEvent(bool wait)
1999 {
2000 	term_data *old_td = (term_data*)(Term->data);
2001 
2002 	XEvent xev_body, *xev = &xev_body;
2003 
2004 	term_data *td = NULL;
2005 	infowin *iwin = NULL;
2006 
2007 	int i;
2008 	int window = 0;
2009 
2010 	/* No pending events? */
2011 	if (!XPending(Metadpy->dpy))
2012 	{
2013 		/* Need to resize/redraw? */
2014 		if (event_pending) scan_pending_windows();
2015 
2016 		/* Do not wait unless requested */
2017 		if (!wait) return (1);
2018 	}
2019 
2020 	/*
2021 	 * Hack - redraw the selection, if needed.
2022 	 * This doesn't actually check that one of its squares was drawn to,
2023 	 * only that this may have happened.
2024 	 */
2025 	if (x11_selection->select && !x11_selection->drawn) mark_selection();
2026 
2027 	/* Load the Event */
2028 	XNextEvent(Metadpy->dpy, xev);
2029 
2030 
2031 	/* Notice new keymaps */
2032 	if (xev->type == MappingNotify)
2033 	{
2034 		XRefreshKeyboardMapping(&xev->xmapping);
2035 		return 0;
2036 	}
2037 
2038 
2039 	/* Scan the windows */
2040 	for (i = 0; i < MAX_TERM_DATA; i++)
2041 	{
2042 		if (xev->xany.window == data[i].win->win)
2043 		{
2044 			td = &data[i];
2045 			iwin = td->win;
2046 			window = i;
2047 			break;
2048 		}
2049 	}
2050 
2051 	/* Unknown window */
2052 	if (!td || !iwin) return (0);
2053 
2054 
2055 	/* Hack -- activate the Term */
2056 	Term_activate(&td->t);
2057 
2058 	/* Hack -- activate the window */
2059 	Infowin_set(iwin);
2060 
2061 
2062 	/* Switch on the Type */
2063 	switch (xev->type)
2064 	{
2065 		case ButtonPress:
2066 		case ButtonRelease:
2067 		{
2068 			bool press = (xev->type == ButtonPress);
2069 
2070 			/* Where is the mouse */
2071 			int x = xev->xbutton.x;
2072 			int y = xev->xbutton.y;
2073 
2074 			int z;
2075 
2076 			/* Which button is involved */
2077 			if (xev->xbutton.button == Button1) z = 1;
2078 			else if (xev->xbutton.button == Button2) z = 2;
2079 			else if (xev->xbutton.button == Button3) z = 3;
2080 			else if (xev->xbutton.button == Button4) z = 4;
2081 			else if (xev->xbutton.button == Button5) z = 5;
2082 			else z = 0;
2083 
2084 			/* XXX Handle */
2085 			handle_button(xev->xbutton.time, x, y, z, press);
2086 
2087 			break;
2088 		}
2089 
2090 		case MotionNotify:
2091 		{
2092 			/* Where is the mouse */
2093 			int x = xev->xmotion.x;
2094 			int y = xev->xmotion.y;
2095 			unsigned int z = xev->xmotion.state;
2096 
2097 			/* Convert to co-ordinates Angband understands. */
2098 			pixel_to_square(&x, &y, x, y);
2099 
2100 			/* Alter the selection if appropriate. */
2101 			copy_x11_cont(x, y, z);
2102 
2103 			break;
2104 		}
2105 
2106 		case SelectionRequest:
2107 		{
2108 			paste_x11_send(&(xev->xselectionrequest));
2109 			break;
2110 		}
2111 
2112 		case SelectionClear:
2113 		{
2114 			x11_selection->select = FALSE;
2115 			mark_selection();
2116 			break;
2117 		}
2118 
2119 		case KeyRelease:
2120 		{
2121 			/* Nothing */
2122 			break;
2123 		}
2124 
2125 		case KeyPress:
2126 		{
2127 			/* Hack -- use "old" term */
2128 			Term_activate(&old_td->t);
2129 
2130 			/* Process the key */
2131 			react_keypress(&(xev->xkey));
2132 
2133 			break;
2134 		}
2135 
2136 		case Expose:
2137 		{
2138 			int x1, x2, y1, y2;
2139 
2140 			/* Hack - if we have a pending resize, ignore */
2141 			if (!event_pending)
2142 			{
2143 				pixel_to_square(&x1, &y1, xev->xexpose.x, xev->xexpose.y);
2144 				pixel_to_square(&x2, &y2, xev->xexpose.x + xev->xexpose.width,
2145 										xev->xexpose.y + xev->xexpose.height);
2146 
2147 				Term_redraw_section(x1, y1, x2, y2);
2148 			}
2149 			else
2150 			{
2151 				/* Make sure to redraw later */
2152 				event_pending = TRUE;
2153 				Infowin->redraw = TRUE;
2154 			}
2155 
2156 			break;
2157 		}
2158 
2159 		case MapNotify:
2160 		{
2161 			Infowin->mapped = 1;
2162 			Term->mapped_flag = TRUE;
2163 			break;
2164 		}
2165 
2166 		case UnmapNotify:
2167 		{
2168 			Infowin->mapped = 0;
2169 			Term->mapped_flag = FALSE;
2170 			break;
2171 		}
2172 
2173 		/* Move and/or Resize */
2174 		case ConfigureNotify:
2175 		{
2176 			int cols, rows, wid, hgt;
2177 
2178 			int ox = Infowin->ox;
2179 			int oy = Infowin->oy;
2180 
2181 			/* Save the new Window Parms */
2182 			Infowin->x = xev->xconfigure.x;
2183 			Infowin->y = xev->xconfigure.y;
2184 
2185 			if ((Infowin->w != xev->xconfigure.width) ||
2186 				(Infowin->h != xev->xconfigure.height))
2187 			{
2188 				Infowin->w = xev->xconfigure.width;
2189 				Infowin->h = xev->xconfigure.height;
2190 
2191 				/* We need to notice the resize of this window (later) */
2192 				Infowin->resize = TRUE;
2193 				event_pending = TRUE;
2194 			}
2195 
2196 			/* Determine "proper" number of rows/cols */
2197 			cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2198 			rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2199 
2200 			/* Hack -- minimal size */
2201 			if (cols < 1) cols = 1;
2202 			if (rows < 1) rows = 1;
2203 
2204 			/* Hack the main window must be at least 80x24 */
2205 			if (i == 0)
2206 			{
2207 				if (cols < 80) cols = 80;
2208 				if (rows < 24) rows = 24;
2209 			}
2210 
2211 			/* Desired size of window */
2212 			wid = cols * td->fnt->wid + (ox + ox);
2213 			hgt = rows * td->fnt->hgt + (oy + oy);
2214 
2215 			/* Resize the windows if any "change" is needed */
2216 			if ((Infowin->w != wid) || (Infowin->h != hgt))
2217 			{
2218 				/* Resize window */
2219 				Infowin_set(td->win);
2220 				Infowin_resize(wid, hgt);
2221 			}
2222 
2223 			break;
2224 		}
2225 	}
2226 
2227 
2228 	/* Hack -- Activate the old term */
2229 	Term_activate(&old_td->t);
2230 
2231 	/* Hack -- Activate the proper window */
2232 	Infowin_set(old_td->win);
2233 
2234 
2235 	/* Success */
2236 	return (0);
2237 }
2238 
2239 
2240 /*
2241  * Handle "activation" of a term
2242  */
Term_xtra_x11_level(int v)2243 static errr Term_xtra_x11_level(int v)
2244 {
2245 	term_data *td = (term_data*)(Term->data);
2246 
2247 	/* Handle "activate" */
2248 	if (v)
2249 	{
2250 		/* Activate the window */
2251 		Infowin_set(td->win);
2252 
2253 		/* Activate the font */
2254 		Infofnt_set(td->fnt);
2255 	}
2256 
2257 	/* Success */
2258 	return (0);
2259 }
2260 
2261 
2262 /*
2263  * React to changes
2264  */
Term_xtra_x11_react(void)2265 static errr Term_xtra_x11_react(void)
2266 {
2267 	int i;
2268 
2269 	if (Metadpy->color)
2270 	{
2271 		/* Check the colors */
2272 		for (i = 0; i < 256; i++)
2273 		{
2274 			if ((color_table[i][0] != angband_color_table[i][0]) ||
2275 			    (color_table[i][1] != angband_color_table[i][1]) ||
2276 			    (color_table[i][2] != angband_color_table[i][2]) ||
2277 			    (color_table[i][3] != angband_color_table[i][3]))
2278 			{
2279 				Pixell pixel;
2280 
2281 				/* Save new values */
2282 				color_table[i][0] = angband_color_table[i][0];
2283 				color_table[i][1] = angband_color_table[i][1];
2284 				color_table[i][2] = angband_color_table[i][2];
2285 				color_table[i][3] = angband_color_table[i][3];
2286 
2287 				/* Create pixel */
2288 				pixel = create_pixel(Metadpy->dpy,
2289 				                     color_table[i][1],
2290 				                     color_table[i][2],
2291 				                     color_table[i][3]);
2292 
2293 				/* Change the foreground */
2294 				Infoclr_set(clr[i]);
2295 				Infoclr_change_fg(pixel);
2296 			}
2297 		}
2298 	}
2299 
2300 	/* Success */
2301 	return (0);
2302 }
2303 
2304 
2305 /*
2306  * Handle a "special request"
2307  */
Term_xtra_x11(int n,int v)2308 static errr Term_xtra_x11(int n, int v)
2309 {
2310 	/* Handle a subset of the legal requests */
2311 	switch (n)
2312 	{
2313 		/* Make a noise */
2314 		case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
2315 
2316 		/* Flush the output XXX XXX */
2317 		case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
2318 
2319 		/* Process random events XXX */
2320 		case TERM_XTRA_BORED: return (CheckEvent(0));
2321 
2322 		/* Process Events XXX */
2323 		case TERM_XTRA_EVENT: return (CheckEvent(v));
2324 
2325 		/* Flush the events XXX */
2326 		case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
2327 
2328 		/* Handle change in the "level" */
2329 		case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
2330 
2331 		/* Delay for some milliseconds */
2332 		case TERM_XTRA_DELAY:
2333 			if (v > 0) usleep(1000 * v);
2334 			return (0);
2335 
2336 		/* React to changes */
2337 		case TERM_XTRA_REACT: return (Term_xtra_x11_react());
2338 	}
2339 
2340 	/* Unknown */
2341 	return (1);
2342 }
2343 
2344 /*
2345  * Draw the cursor as a rectangular outline
2346  */
Term_curs_x11(int x,int y)2347 static errr Term_curs_x11(int x, int y)
2348 {
2349 	int x1, y1;
2350 	square_to_pixel(&x1, &y1, x, y);
2351 
2352 	if (is_bigtiled(x, y))
2353 	{
2354 		XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2355 			 x1, y1,
2356 			 Infofnt->twid - 1, Infofnt->hgt - 1);
2357 	}
2358 	else
2359 	{
2360 		XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2361 			 x1, y1,
2362 			 Infofnt->wid - 1, Infofnt->hgt - 1);
2363 	}
2364 
2365 	/* Success */
2366 	return (0);
2367 }
2368 
2369 
2370 /*
2371  * Erase some characters.
2372  */
Term_wipe_x11(int x,int y,int n)2373 static errr Term_wipe_x11(int x, int y, int n)
2374 {
2375 	/* Erase (use black) */
2376 	Infoclr_set(clr[TERM_DARK]);
2377 
2378 	/* Erase some space */
2379 	Infofnt_text_non(x, y, n);
2380 
2381 	/* Redraw the selection if any, as it may have been obscured. (later) */
2382 	x11_selection->drawn = FALSE;
2383 
2384 	/* Success */
2385 	return (0);
2386 }
2387 
2388 
2389 /*
2390  * Draw some textual characters.
2391  */
Term_text_x11(int x,int y,int n,byte a,cptr s)2392 static errr Term_text_x11(int x, int y, int n, byte a, cptr s)
2393 {
2394 	/* Erase area first */
2395 	Term_wipe_x11(x, y, n);
2396 
2397 	/* Draw the text */
2398 	Infoclr_set(clr[a]);
2399 
2400 	/* Draw the text */
2401 	Infofnt_text_std(x, y, s, n);
2402 
2403 	/* Redraw the selection if any, as it may have been obscured. (later) */
2404 	x11_selection->drawn = FALSE;
2405 
2406 	/* Success */
2407 	return (0);
2408 }
2409 
2410 
2411 #ifdef USE_GRAPHICS
2412 
2413 
2414 
2415 
2416 /*
2417  * Draw some graphical characters.
2418  */
Term_pict_x11(int ox,int oy,int n,const byte * ap,const char * cp,const byte * tap,const char * tcp)2419 static errr Term_pict_x11(int ox, int oy, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
2420 {
2421 	int i;
2422 	int x1 = 0, y1 = 0;
2423 
2424 	byte a;
2425 	char c;
2426 
2427 	byte ta;
2428 	char tc;
2429 
2430 	int x, y;
2431 	int x2, y2;
2432 	int k,l;
2433 
2434 	unsigned long pixel, blank;
2435 
2436 	term_data *td = (term_data*)(Term->data);
2437 
2438 	int wid, hgt = td->fnt->hgt;
2439 	XImage *tiles;
2440 
2441 	/* Starting point */
2442 	square_to_pixel(&x, &y, ox, oy);
2443 
2444 	for (i = 0; i < n; ++i)
2445 	{
2446 		a = *ap++;
2447 		c = *cp++;
2448 
2449 		ta = *tap++;
2450 		tc = *tcp++;
2451 
2452 		/* What are we drawing? */
2453 		if (is_bigtiled(ox + i, oy))
2454 		{
2455 			tiles = td->b_tiles;
2456 			wid = td->fnt->twid;
2457 		}
2458 		else
2459 		{
2460 			tiles = td->tiles;
2461 			wid = td->fnt->wid;
2462 		}
2463 
2464 		/* For extra speed - cache these values */
2465 		x1 = (c & 0x7F) * wid;
2466 		y1 = (a & 0x7F) * hgt;
2467 
2468 		/* For extra speed - cache these values */
2469 		x2 = (tc & 0x7F) * wid;
2470 		y2 = (ta & 0x7F) * hgt;
2471 
2472 		/* Optimise the common case */
2473 		if (((x1 == x2) && (y1 == y2)) ||
2474 		    !(((byte)ta & 0x80) && ((byte)tc & 0x80)))
2475 		{
2476 			/* Draw object / terrain */
2477 			XPutImage(Metadpy->dpy, td->win->win,
2478 						clr[0]->gc,
2479 						tiles,
2480 						x1, y1,
2481 						x, y,
2482 						wid, hgt);
2483 		}
2484 		else
2485 		{
2486 			/* Mega Hack^2 - assume the top left corner is "blank" */
2487 			if (arg_graphics == GRAPHICS_DAVID_GERVAIS)
2488 				blank = XGetPixel(tiles, 0, 0);
2489 			else
2490 				blank = XGetPixel(tiles, 0, hgt * 6);
2491 
2492 			for (k = 0; k < wid; k++)
2493 			{
2494 				for (l = 0; l < hgt; l++)
2495 				{
2496 					/* If mask set... */
2497 					if ((pixel = XGetPixel(tiles, x1 + k, y1 + l)) == blank)
2498 					{
2499 						/* Output from the terrain */
2500 						pixel = XGetPixel(tiles, x2 + k, y2 + l);
2501 
2502 						if (pixel == blank) pixel = 0L;
2503 					}
2504 
2505 					/* Store into the temp storage. */
2506 					XPutPixel(td->TmpImage, k, l, pixel);
2507 				}
2508 			}
2509 
2510 
2511 			/* Draw to screen */
2512 			XPutImage(Metadpy->dpy, td->win->win,
2513 						clr[0]->gc,
2514 						td->TmpImage,
2515 						0, 0, x, y,
2516 						wid, hgt);
2517 		}
2518 
2519 		x += wid;
2520 	}
2521 
2522 	/* Redraw the selection if any, as it may have been obscured. (later) */
2523 	x11_selection->drawn = FALSE;
2524 
2525 	/* Success */
2526 	return (0);
2527 }
2528 
2529 #endif /* USE_GRAPHICS */
2530 
2531 
2532 
2533 /*
2534  * Initialize a term_data
2535  */
term_data_init(term_data * td,int i)2536 static errr term_data_init(term_data *td, int i)
2537 {
2538 	term *t = &td->t;
2539 
2540 	cptr name = angband_term_name[i];
2541 
2542 	cptr font;
2543 
2544 	int x = 0;
2545 	int y = 0;
2546 
2547 	int cols = 80;
2548 	int rows = 24;
2549 
2550 	int ox = 1;
2551 	int oy = 1;
2552 
2553 	int wid, hgt, num;
2554 
2555 	char buf[80];
2556 
2557 	cptr str;
2558 
2559 	int val;
2560 
2561 	XClassHint *ch;
2562 
2563 	char res_name[20];
2564 	char res_class[20];
2565 
2566 	XSizeHints *sh;
2567 
2568 	/* Get default font for this term */
2569 	font = get_default_font(i);
2570 
2571 	/* Window specific location (x) */
2572 	strnfmt(buf, sizeof(buf), "ANGBAND_X11_AT_X_%d", i);
2573 	str = getenv(buf);
2574 	x = (str != NULL) ? atoi(str) : -1;
2575 
2576 	/* Window specific location (y) */
2577 	strnfmt(buf, sizeof(buf), "ANGBAND_X11_AT_Y_%d", i);
2578 	str = getenv(buf);
2579 	y = (str != NULL) ? atoi(str) : -1;
2580 
2581 	/* Window specific cols */
2582 	strnfmt(buf, sizeof(buf), "ANGBAND_X11_COLS_%d", i);
2583 	str = getenv(buf);
2584 	val = (str != NULL) ? atoi(str) : -1;
2585 	if (val > 0) cols = val;
2586 
2587 	/* Window specific rows */
2588 	strnfmt(buf, sizeof(buf), "ANGBAND_X11_ROWS_%d", i);
2589 	str = getenv(buf);
2590 	val = (str != NULL) ? atoi(str) : -1;
2591 	if (val > 0) rows = val;
2592 
2593 	/* Hack the main window must be at least 80x24 */
2594 	if (!i)
2595 	{
2596 		if (cols < 80) cols = 80;
2597 		if (rows < 24) rows = 24;
2598 	}
2599 
2600 	/* Window specific inner border offset (ox) */
2601 	strnfmt(buf, sizeof(buf), "ANGBAND_X11_IBOX_%d", i);
2602 	str = getenv(buf);
2603 	val = (str != NULL) ? atoi(str) : -1;
2604 	if (val > 0) ox = val;
2605 
2606 	/* Window specific inner border offset (oy) */
2607 	strnfmt(buf, sizeof(buf), "ANGBAND_X11_IBOY_%d", i);
2608 	str = getenv(buf);
2609 	val = (str != NULL) ? atoi(str) : -1;
2610 	if (val > 0) oy = val;
2611 
2612 
2613 	/* Prepare the standard font */
2614 	MAKE(td->fnt, infofnt);
2615 	Infofnt_set(td->fnt);
2616 	if (Infofnt_init_data(font))
2617 	{
2618 		quit("Stopping");
2619 	}
2620 
2621 	/* Hack -- key buffer size */
2622 	num = ((i == 0) ? 1024 : 16);
2623 
2624 	/* Assume full size windows */
2625 	wid = cols * td->fnt->wid + (ox + ox);
2626 	hgt = rows * td->fnt->hgt + (oy + oy);
2627 
2628 	/* Create a top-window */
2629 	MAKE(td->win, infowin);
2630 	Infowin_set(td->win);
2631 	Infowin_init_top(x, y, wid, hgt, 0,
2632 	                 Metadpy->fg, Metadpy->bg);
2633 
2634 	/* Ask for certain events */
2635 	Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask |
2636 	                 PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
2637 
2638 	/* Set the window name */
2639 	Infowin_set_name(name);
2640 
2641 	/* Save the inner border */
2642 	Infowin->ox = ox;
2643 	Infowin->oy = oy;
2644 
2645 	/* Make Class Hints */
2646 	ch = XAllocClassHint();
2647 
2648 	if (ch == NULL) quit("XAllocClassHint failed");
2649 
2650 	strnfmt(res_name, sizeof(res_name), "%s", name);
2651 	res_name[0] = FORCELOWER(res_name[0]);
2652 	ch->res_name = res_name;
2653 
2654 	strnfmt(res_class, sizeof(res_class), "Angband");
2655 	ch->res_class = res_class;
2656 
2657 	XSetClassHint(Metadpy->dpy, Infowin->win, ch);
2658 
2659 	/* Make Size Hints */
2660 	sh = XAllocSizeHints();
2661 
2662 	/* Oops */
2663 	if (sh == NULL) quit("XAllocSizeHints failed");
2664 
2665 	/* Main window has a differing minimum size */
2666 	if (i == 0)
2667 	{
2668 		/* Main window min size is 80x24 */
2669 		sh->flags = PMinSize | PMaxSize;
2670 		sh->min_width = 80 * td->fnt->wid + (ox + ox);
2671 		sh->min_height = 24 * td->fnt->hgt + (oy + oy);
2672 		sh->max_width = 255 * td->fnt->wid + (ox + ox);
2673 		sh->max_height = 255 * td->fnt->hgt + (oy + oy);
2674 	}
2675 
2676 	/* Other windows can be shrunk to 1x1 */
2677 	else
2678 	{
2679 		/* Other windows */
2680 		sh->flags = PMinSize | PMaxSize;
2681 		sh->min_width = td->fnt->wid + (ox + ox);
2682 		sh->min_height = td->fnt->hgt + (oy + oy);
2683 		sh->max_width = 255 * td->fnt->wid + (ox + ox);
2684 		sh->max_height = 255 * td->fnt->hgt + (oy + oy);
2685 	}
2686 
2687 	/* Resize increment */
2688 	sh->flags |= PResizeInc;
2689 	sh->width_inc = td->fnt->wid;
2690 	sh->height_inc = td->fnt->hgt;
2691 
2692 	/* Base window size */
2693 	sh->flags |= PBaseSize;
2694 	sh->base_width = (ox + ox);
2695 	sh->base_height = (oy + oy);
2696 
2697 	/* Use the size hints */
2698 	XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
2699 
2700 	/* Map the window */
2701 	Infowin_map();
2702 
2703 
2704 	/* Move the window to requested location */
2705 	if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
2706 
2707 
2708 	/* Initialize the term */
2709 	term_init(t, cols, rows, num);
2710 
2711 	/* Use a "soft" cursor */
2712 	t->soft_cursor = TRUE;
2713 
2714 	/* Erase with "black space" */
2715 	t->attr_blank = TERM_DARK;
2716 	t->char_blank = ' ';
2717 
2718 	/* Hooks */
2719 	t->xtra_hook = Term_xtra_x11;
2720 	t->curs_hook = Term_curs_x11;
2721 	t->wipe_hook = Term_wipe_x11;
2722 	t->text_hook = Term_text_x11;
2723 
2724 	/* Save the data */
2725 	t->data = td;
2726 
2727 	/* Activate (important) */
2728 	Term_activate(t);
2729 
2730 	/* Success */
2731 	return (0);
2732 }
2733 
2734 
2735 /*
2736  * Initialization function for an "X11" module to Angband
2737  */
init_x11(int argc,char * argv[])2738 errr init_x11(int argc, char *argv[])
2739 {
2740 	int i;
2741 
2742 	cptr dpy_name = "";
2743 
2744 	int num_term = 3;
2745 
2746 #ifdef USE_GRAPHICS
2747 
2748 	char filename[1024];
2749 
2750 	int pict_wid = 0;
2751 	int pict_hgt = 0;
2752 
2753 	int graphmode = GRAPHICS_ANY;
2754 
2755 	char *TmpData;
2756 
2757 #endif /* USE_GRAPHICS */
2758 
2759 
2760 	/* Parse args */
2761 	for (i = 1; i < argc; i++)
2762 	{
2763 		if (prefix(argv[i], "-d"))
2764 		{
2765 			dpy_name = &argv[i][2];
2766 			continue;
2767 		}
2768 
2769 #ifdef USE_GRAPHICS
2770 		if (prefix(argv[i], "-s"))
2771 		{
2772 			smoothRescaling = FALSE;
2773 			continue;
2774 		}
2775 
2776 		if (prefix(argv[i], "-b"))
2777 		{
2778 			int bitdepth = 0;
2779 
2780 			bitdepth = atoi(&argv[i][2]);
2781 
2782 			/* Paranoia */
2783 			if (bitdepth == 32) graphmode = GRAPHICS_DAVID_GERVAIS;
2784 			if (bitdepth == 16) graphmode = GRAPHICS_ADAM_BOLT;
2785 			if (bitdepth == 8) graphmode = GRAPHICS_ORIGINAL;
2786 
2787 			continue;
2788 		}
2789 #endif /* USE_GRAPHICS */
2790 
2791 		if (prefix(argv[i], "-n"))
2792 		{
2793 			num_term = atoi(&argv[i][2]);
2794 			if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
2795 			else if (num_term < 1) num_term = 1;
2796 			continue;
2797 		}
2798 
2799 		plog_fmt("Ignoring option: %s", argv[i]);
2800 	}
2801 
2802 
2803 	/* Init the Metadpy if possible */
2804 	if (Metadpy_init_name(dpy_name)) return (-1);
2805 
2806 #ifdef USE_GRAPHICS
2807 	/* We support bigtile mode */
2808 	if (arg_bigtile && arg_graphics) use_bigtile = TRUE;
2809 #endif /* USE_GRAPHICS */
2810 
2811 	/* Prepare cursor color */
2812 	MAKE(xor, infoclr);
2813 	Infoclr_set(xor);
2814 	Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
2815 
2816 
2817 	/* Prepare normal colors */
2818 	for (i = 0; i < 256; ++i)
2819 	{
2820 		Pixell pixel;
2821 
2822 		MAKE(clr[i], infoclr);
2823 
2824 		Infoclr_set(clr[i]);
2825 
2826 		/* Acquire Angband colors */
2827 		color_table[i][0] = angband_color_table[i][0];
2828 		color_table[i][1] = angband_color_table[i][1];
2829 		color_table[i][2] = angband_color_table[i][2];
2830 		color_table[i][3] = angband_color_table[i][3];
2831 
2832 		/* Default to monochrome */
2833 		pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
2834 
2835 		/* Handle color */
2836 		if (Metadpy->color)
2837 		{
2838 			/* Create pixel */
2839 			pixel = create_pixel(Metadpy->dpy,
2840 			                     color_table[i][1],
2841 			                     color_table[i][2],
2842 			                     color_table[i][3]);
2843 		}
2844 
2845 		/* Initialize the color */
2846 		Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
2847 	}
2848 
2849 
2850 	/* Initialize the windows */
2851 	for (i = 0; i < num_term; i++)
2852 	{
2853 		term_data *td = &data[i];
2854 
2855 		/* Initialize the term_data */
2856 		term_data_init(td, i);
2857 
2858 		/* Save global entry */
2859 		angband_term[i] = Term;
2860 	}
2861 
2862 
2863 #ifdef USE_GRAPHICS
2864 	/* Try graphics */
2865 	if (arg_graphics)
2866 	{
2867 		(void) pick_graphics(graphmode, &pict_wid, &pict_hgt, filename);
2868 	}
2869 
2870 	/* Load graphics */
2871 	if (use_graphics)
2872 	{
2873 		Display *dpy = Metadpy->dpy;
2874 
2875 		XImage *tiles_raw;
2876 
2877 		/* Initialize */
2878 		for (i = 0; i < num_term; i++)
2879 		{
2880 			term_data *td = &data[i];
2881 			td->tiles = NULL;
2882 		}
2883 
2884 		/* Load the graphical tiles */
2885 		tiles_raw = ReadBMP(dpy, filename);
2886 
2887 		if (tiles_raw)
2888 		{
2889 			/* Initialize the windows */
2890 			for (i = 0; i < num_term; i++)
2891 			{
2892 				int j;
2893 
2894 				term_data *td = &data[i];
2895 				term_data *o_td = NULL;
2896 
2897 				term *t = &td->t;
2898 
2899 				/* Graphics hook */
2900 				t->pict_hook = Term_pict_x11;
2901 
2902 				/* Use graphics sometimes */
2903 				t->higher_pict = TRUE;
2904 
2905 				/* Look for another term with same font size */
2906 				for (j = 0; j < i; j++)
2907 				{
2908 					o_td = &data[j];
2909 
2910 					if ((td->fnt->wid == o_td->fnt->wid) && (td->fnt->hgt == o_td->fnt->hgt))
2911 					{
2912 						/* Use same graphics */
2913 						td->tiles = o_td->tiles;
2914 						td->b_tiles = o_td->b_tiles;
2915 						break;
2916 					}
2917 				}
2918 
2919 				/* Resize Tiles */
2920 				if (!td->tiles)
2921 				{
2922 					if (arg_bigtile)
2923 					{
2924 						td->b_tiles = ResizeImage(dpy, tiles_raw,
2925 													pict_wid, pict_hgt,
2926 													td->fnt->twid, td->fnt->hgt);
2927 					}
2928 					else
2929 					{
2930 						td->b_tiles = NULL;
2931 					}
2932 					td->tiles = ResizeImage(dpy, tiles_raw,
2933 					                        pict_wid, pict_hgt,
2934 					                        td->fnt->wid, td->fnt->hgt);
2935 				}
2936 			}
2937 
2938 			/* Free tiles_raw */
2939 			FREE(tiles_raw);
2940 		}
2941 
2942 		/* Initialize the transparency masks */
2943 		for (i = 0; i < num_term; i++)
2944 		{
2945 			term_data *td = &data[i];
2946 			int ii, jj;
2947 			int depth = DefaultDepth(dpy, DefaultScreen(dpy));
2948 			Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
2949 			int total;
2950 
2951 			/* Determine total bytes needed for image */
2952 			ii = 1;
2953 			jj = (depth - 1) >> 2;
2954 			while (jj >>= 1) ii <<= 1;
2955 
2956 			/* Pad the scanline to a multiple of 4 bytes */
2957 			total = td->fnt->twid * ii;
2958 			total = (total + 3) & ~3;
2959 			total *= td->fnt->hgt;
2960 
2961 			TmpData = (char *)malloc(total);
2962 
2963 			td->TmpImage = XCreateImage(dpy,visual,depth,
2964 				ZPixmap, 0, TmpData,
2965 				td->fnt->twid, td->fnt->hgt, 32, 0);
2966 		}
2967 	}
2968 
2969 #endif /* USE_GRAPHICS */
2970 
2971 	/* Raise the "Angband" window */
2972 	Infowin_set(data[0].win);
2973 	Infowin_raise();
2974 
2975 	/* Activate the "Angband" window screen */
2976 	Term_activate(&data[0].t);
2977 
2978 	/* Success */
2979 	return (0);
2980 }
2981 
2982 #endif /* USE_X11 */
2983