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