1 /* File: main-x11.c */
4 * Copyright (c) 1997 Ben Harrison, and others
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.
13 * This file helps Angband work with UNIX/X11 computers.
15 * To use this file, compile with "USE_X11" defined, and link against all
16 * the various "X11" libraries which may be needed.
18 * See also "main-xaw.c".
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
26 * The rest of this file is an implementation of "main-xxx.c" for X11.
28 * Most of this file is by Ben Harrison (benh@phial.com).
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.
44 * echo "Launching angband..."
48 * setenv ANGBAND_X11_FONT_0 10x20
49 * setenv ANGBAND_X11_AT_X_0 5
50 * setenv ANGBAND_X11_AT_Y_0 510
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
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_3 23
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
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
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
84 * # The build directory
88 * setenv ANGBAND_X11_GAMMA 142
91 * ./src/angband -mx11 -- -n6 &
95 #include "system/angband.h"
96 #include "cmd-io/macro-util.h"
97 #include "game-option/runtime-arguments.h"
98 #include "game-option/special-options.h"
99 #include "io/files-util.h"
100 #include "main/sound-definitions-table.h"
101 #include "main/sound-of-music.h"
102 #include "main/x11-type-string.h"
103 #include "system/system-variables.h"
104 #include "term/gameterm.h"
105 #include "term/term-color-types.h"
106 #include "util/int-char-converter.h"
107 #include "util/angband-files.h"
108 #include "util/string-processor.h"
111 * Available graphic modes
113 #define GRAPHICS_NONE 0
114 #define GRAPHICS_ORIGINAL 1
115 #define GRAPHICS_ADAM_BOLT 2
116 #define GRAPHICS_HENGBAND 3
118 #ifndef __MAKEDEPEND__
119 #include <X11/Xlib.h>
120 #include <X11/Xutil.h>
121 #include <X11/keysym.h>
122 #include <X11/keysymdef.h>
124 #include <X11/Xlocale.h>
126 #include <X11/Xatom.h>
127 #endif /* __MAKEDEPEND__ */
131 #include <X11/Xft/Xft.h>
135 * Include some helpful X11 code.
137 #include "maid-x11.c"
143 * 1) On a monochrome (or "fake-monochrome") display, all colors
144 * will be "cast" to "fg," except for the bg color, which is,
145 * obviously, cast to "bg". Thus, one can ignore this setting.
147 * 2) Because of the inner functioning of the color allocation
148 * routines, colors may be specified as (a) a typical color name,
149 * (b) a hexidecimal color specification (preceded by a pound sign),
150 * or (c) by strings such as "fg", "bg", "zg".
152 * 3) Due to the workings of the init routines, many colors
153 * may also be dealt with by their actual pixel values. Note that
154 * the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
155 * is not necessarily either black or white.
158 /**** Generic Types ****/
161 * An X11 pixell specifier
164 typedef XftColor Pixell;
166 typedef unsigned long Pixell;
170 * The structures defined below
172 typedef struct metadpy metadpy;
173 typedef struct infowin infowin;
174 typedef struct infoclr infoclr;
175 typedef struct infofnt infofnt;
178 * A structure summarizing a given Display.
180 * - The Display itself
181 * - The default Screen for the display
182 * - The virtual root (usually just the root)
183 * - The default colormap (from a macro)
185 * - The "name" of the display
187 * - The socket to listen to for events
189 * - The width of the display screen (from a macro)
190 * - The height of the display screen (from a macro)
191 * - The bit depth of the display screen (from a macro)
193 * - The black Pixell (from a macro)
194 * - The white Pixell (from a macro)
196 * - The background Pixell (default: black)
197 * - The foreground Pixell (default: white)
198 * - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
200 * - Bit Flag: Force all colors to black and white (default: !color)
201 * - Bit Flag: Allow the use of color (default: depth > 1)
202 * - Bit Flag: We created 'dpy', and so should nuke it when done.
237 * A Structure summarizing Window Information.
239 * I assume that a window is at most 30000 pixels on a side.
240 * I assume that the root windw is also at most 30000 square.
243 * - The current Input Event Mask
245 * - The location of the window
246 * - The width, height of the window
247 * - The border width of this window
249 * - Byte: 1st Extra byte
251 * - Bit Flag: This window is currently Mapped
252 * - Bit Flag: This window needs to be redrawn
253 * - Bit Flag: This window has been resized
255 * - Bit Flag: We should nuke 'win' when done with it
257 * - Bit Flag: 1st extra flag
258 * - Bit Flag: 2nd extra flag
259 * - Bit Flag: 3rd extra flag
260 * - Bit Flag: 4th extra flag
296 * A Structure summarizing Operation+Color Information
298 * - The actual GC corresponding to this info
300 * - The Foreground Pixell Value
301 * - The Background Pixell Value
303 * - Num (0-15): The operation code (As in Clear, Xor, etc)
304 * - Bit Flag: The GC is in stipple mode
305 * - Bit Flag: Destroy 'gc' at Nuke time.
322 * A Structure to Hold Font Information
324 * - The 'XFontStruct*' (yields the 'Font')
328 * - The default character width
329 * - The default character height
330 * - The default character ascent
332 * - Byte: Pixel offset used during fake mono
334 * - Flag: Force monospacing via 'wid'
335 * - Flag: Nuke info when done
357 /* Set current metadpy (Metadpy) to 'M' */
358 #define Metadpy_set(M) \
361 /* Initialize 'M' using Display 'D' */
362 #define Metadpy_init_dpy(D) \
363 Metadpy_init_2(D,cNULL)
365 /* Initialize 'M' using a Display named 'N' */
366 #define Metadpy_init_name(N) \
367 Metadpy_init_2((Display*)(NULL),N)
369 /* Initialize 'M' using the standard Display */
370 #define Metadpy_init() \
371 Metadpy_init_name("")
373 /* Init an infowin by giving father as an (info_win*) (or NULL), and data */
374 #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
375 Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
378 /* Init a top level infowin by pos,size,bord,Colors */
379 #define Infowin_init_top(X,Y,W,H,B,FG,BG) \
380 Infowin_init_data(None,X,Y,W,H,B,FG,BG)
382 /* Request a new standard window by giving Dad infowin and X,Y,W,H */
383 #define Infowin_init_std(D,X,Y,W,H,B) \
384 Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
386 /* Set the current Infowin */
387 #define Infowin_set(I) \
390 /* Set the current Infoclr */
391 #define Infoclr_set(C) \
394 #define Infoclr_init_ppo(F,B,O,M) \
395 Infoclr_init_data(F,B,O,M)
397 #define Infoclr_init_cco(F,B,O,M) \
398 Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
400 #define Infoclr_init_ppn(F,B,O,M) \
401 Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
403 #define Infoclr_init_ccn(F,B,O,M) \
404 Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
406 /* Set the current infofnt */
407 #define Infofnt_set(I) \
410 /* Errr: Expose Infowin */
411 #define Infowin_expose() \
412 (!(Infowin->redraw = 1))
414 /* Errr: Unxpose Infowin */
415 #define Infowin_unexpose() \
416 (Infowin->redraw = 0)
419 * The "default" values
421 static metadpy metadpy_default;
424 * The "current" variables
426 static metadpy *Metadpy = &metadpy_default;
427 static infowin *Infowin = (infowin*)(NULL);
429 static infowin *Focuswin = (infowin*)(NULL);
431 static infoclr *Infoclr = (infoclr*)(NULL);
432 static infofnt *Infofnt = (infofnt*)(NULL);
435 * Init the current metadpy, with various initialization stuff.
438 * dpy: The Display* to use (if NULL, create it)
439 * name: The name of the Display (if NULL, the current)
442 * If 'name' is NULL, but 'dpy' is set, extract name from dpy
443 * If 'dpy' is NULL, then Create the named Display
444 * If 'name' is NULL, and so is 'dpy', use current Display
446 * Return -1 if no Display given, and none can be opened.
448 static errr Metadpy_init_2(Display *dpy, concptr name)
450 metadpy *m = Metadpy;
453 dpy = XOpenDisplay(name);
454 if (!dpy) return (-1);
464 m->screen = DefaultScreenOfDisplay(dpy);
465 m->root = RootWindowOfScreen(m->screen);
466 m->cmap = DefaultColormapOfScreen(m->screen);
467 m->name = DisplayString(dpy);
468 m->fd = ConnectionNumber(Metadpy->dpy);
469 m->width = WidthOfScreen(m->screen);
470 m->height = HeightOfScreen(m->screen);
471 m->depth = DefaultDepthOfScreen(m->screen);
474 Visual *vis = DefaultVisual(dpy, 0);
475 XftColorAllocName(dpy, vis, m->cmap, "black", &m->black);
476 XftColorAllocName(dpy, vis, m->cmap, "white", &m->white);
478 m->black = BlackPixelOfScreen(m->screen);
479 m->white = WhitePixelOfScreen(m->screen);
486 m->zg = (1 << m->depth) - 1;
489 m->color = ((m->depth > 1) ? 1 : 0);
490 m->mono = ((m->color) ? 0 : 1);
495 * General Flush/ Sync/ Discard routine
497 static errr Metadpy_update(int flush, int sync, int discard)
499 if (flush) XFlush(Metadpy->dpy);
500 if (sync) XSync(Metadpy->dpy, discard);
509 static errr Metadpy_do_beep(void)
511 XBell(Metadpy->dpy, 100);
516 * Set the name (in the title bar) of Infowin
518 static errr Infowin_set_name(concptr name)
525 st = XStringListToTextProperty(&bp, 1, &tp);
526 if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
531 * Prepare a new 'infowin'.
533 static errr Infowin_prepare(Window xid)
535 infowin *iwin = Infowin;
537 XWindowAttributes xwa;
539 unsigned int w, h, b, d;
541 XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
544 Visual *vis = DefaultVisual(Metadpy->dpy, 0);
545 if (vis->class != TrueColor) {
546 quit_fmt("Display does not support truecolor.\n");
548 iwin->draw = XftDrawCreate(Metadpy->dpy, iwin->win, vis, Metadpy->cmap);
557 XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
558 iwin->mask = xwa.your_event_mask;
559 iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
565 * Init an infowin by giving some data.
568 * dad: The Window that should own this Window (if any)
569 * x,y: The position of this Window
570 * w,h: The size of this Window
571 * b,d: The border width and pixel depth
574 * If 'dad == None' assume 'dad == root'
576 static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
577 int b, Pixell fg, Pixell bg)
580 (void)WIPE(Infowin, infowin);
581 if (dad == None) dad = Metadpy->root;
584 xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg.pixel, bg.pixel);
586 xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
589 XSelectInput(Metadpy->dpy, xid, 0L);
591 return (Infowin_prepare(xid));
595 * Modify the event mask of an Infowin
597 static errr Infowin_set_mask(long mask)
599 Infowin->mask = mask;
600 XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
605 * Request that Infowin be mapped
607 static errr Infowin_map(void)
609 XMapWindow(Metadpy->dpy, Infowin->win);
614 * Request that Infowin be raised
616 static errr Infowin_raise(void)
618 XRaiseWindow(Metadpy->dpy, Infowin->win);
623 * Request that Infowin be moved to a new location
625 static errr Infowin_impell(int x, int y)
627 XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
634 static errr Infowin_resize(int w, int h)
636 XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
641 * Visually clear Infowin
643 static errr Infowin_wipe(void)
645 XClearWindow(Metadpy->dpy, Infowin->win);
650 * A NULL terminated pair list of legal "operation names"
652 * Pairs of values, first is texttual name, second is the string
653 * holding the decimal value that the operation corresponds to.
655 static concptr opcode_pairs[] =
674 "+copyInverted", "12",
681 * Parse a word into an operation "code"
684 * str: A string, hopefully representing an Operation
687 * 0-15: if 'str' is a valid Operation
688 * -1: if 'str' could not be parsed
690 static int Infoclr_Opcode(concptr str)
693 for (i = 0; opcode_pairs[i*2]; ++i)
695 if (streq(opcode_pairs[i*2], str))
697 return (atoi(opcode_pairs[i*2+1]));
705 * Initialize an infoclr with some data
708 * fg: The Pixell for the requested Foreground (see above)
709 * bg: The Pixell for the requested Background (see above)
710 * op: The Opcode for the requested Operation (see above)
711 * stip: The stipple mode
713 static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
715 infoclr *iclr = Infoclr;
720 unsigned long gc_mask;
724 if (bg > Metadpy->zg) return (-1);
725 if (fg > Metadpy->zg) return (-1);
726 if ((op < 0) || (op > 15)) return (-1);
731 if (op == 6) gcv.background = 0;
732 if (op == 6) gcv.foreground = (bg ^ fg);
734 gcv.fill_style = (stip ? FillStippled : FillSolid);
735 gcv.graphics_exposures = False;
736 gc_mask = (GCFunction | GCBackground | GCForeground | GCFillStyle | GCGraphicsExposures);
737 gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
740 (void)WIPE(iclr, infoclr);
750 iclr->stip = stip ? 1 : 0;
755 * Change the 'fg' for an infoclr
758 * fg: The Pixell for the requested Foreground (see above)
760 static errr Infoclr_change_fg(Pixell fg)
762 infoclr *iclr = Infoclr;
767 if (fg > Metadpy->zg) return (-1);
769 XSetForeground(Metadpy->dpy, iclr->gc, fg);
776 * Prepare a new 'infofnt'
779 static errr Infofnt_prepare(XftFont *info)
781 static errr Infofnt_prepare(XFontSet info)
784 infofnt *ifnt = Infofnt;
788 XFontStruct **fontinfo;
791 int ascent, descent, width;
798 ifnt->asc = info->ascent;
799 ifnt->hgt = info->ascent + info->descent;
800 const char *text = "A";
802 XftTextExtentsUtf8(Metadpy->dpy, info, (FcChar8*)text, strlen(text), &extent);
803 ifnt->wid = extent.xOff;
805 n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);
807 ascent = descent = width = 0;
808 while(n_fonts-- > 0){
809 cs = &((*fontinfo)->max_bounds);
810 if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
811 if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
812 if(((*fontinfo)->max_byte1) > 0){
813 /* 多バイト文字の場合は幅半分(端数切り上げ)で評価する */
814 if(width < (cs->width+1)/2) width = (cs->width+1)/2;
816 if(width < cs->width) width = cs->width;
822 ifnt->hgt = ascent + descent;
827 ifnt->twid = 2 * ifnt->wid;
829 ifnt->twid = ifnt->wid;
835 * Init an infofnt by its Name
838 * name: The name of the requested Font
840 static void Infofnt_init_data(concptr name)
852 if (!name || !*name) quit("Missing font!");
855 info = XftFontOpenName(Metadpy->dpy, 0, name);
856 /* TODO: error handling */
858 info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
859 if(missing_count > 0){
860 printf("missing font(s): \n");
861 while(missing_count-- > 0){
862 printf("\t%s\n", missing_list[missing_count]);
864 XFreeStringList(missing_list);
868 if (!info) quit_fmt("Failed to find font:\"%s\"", name);
870 (void)WIPE(Infofnt, infofnt);
871 if (Infofnt_prepare(info))
874 XftFontClose(Metadpy->dpy, info);
876 XFreeFontSet(Metadpy->dpy, info);
878 quit_fmt("Failed to prepare font:\"%s\"", name);
881 Infofnt->name = string_make(name);
888 static errr Infofnt_text_std(int x, int y, concptr str, int len)
890 if (!str || !*str) return (-1);
892 if (len < 0) len = strlen(str);
894 y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
895 x = (x * Infofnt->wid) + Infowin->ox;
900 for (i = 0; i < len; ++i)
902 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc, x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
908 iconv_t cd = iconv_open("UTF-8", "EUC-JP");
910 size_t outlen = len * 2;
911 char *kanji = malloc(outlen);
912 char *sp; char *kp = kanji;
914 memcpy(sbuf, str, (size_t)len);
916 iconv(cd, &sp, &inlen, &kp, &outlen);
920 XftDraw* draw = Infowin->draw;
925 r.width = Infofnt->wid*len;
926 r.height = Infofnt->hgt;
927 XftDrawSetClipRectangles(draw, x, y-Infofnt->asc, &r, 1);
928 XftDrawRect(draw, &Infoclr->bg, x, y-Infofnt->asc, Infofnt->wid*len, Infofnt->hgt);
929 XftDrawStringUtf8(draw, &Infoclr->fg, Infofnt->info, x, y,
930 (FcChar8*)kanji, kp - kanji);
931 XftDrawSetClip(draw, 0);
933 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
934 Infoclr->gc, x, y, kanji, kp-kanji);
943 * Painting where text would be
945 static errr Infofnt_text_non(int x, int y, concptr str, int len)
948 if (len < 0) len = strlen(str);
950 w = len * Infofnt->wid;
951 x = x * Infofnt->wid + Infowin->ox;
953 y = y * h + Infowin->oy;
956 XftDrawRect(Infowin->draw, &Infoclr->fg, x, y, w, h);
958 XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
965 * Angband specific code follows... (ANGBAND)
969 * Hack -- cursor color
976 static infoclr *clr[256];
979 * Color info (unused, red, green, blue).
981 static byte color_table[256][4];
986 typedef struct term_data term_data;
989 * A structure for each "term"
1003 * The number of term data structures
1005 #define MAX_TERM_DATA 8
1008 * The array of term data structures
1010 static term_data data[MAX_TERM_DATA];
1013 /* Use short names for the most commonly used elements of various structures. */
1014 #define DPY (Metadpy->dpy)
1015 #define WIN (Infowin->win)
1017 /* Describe a set of co-ordinates. */
1018 typedef struct co_ord co_ord;
1026 * A special structure to store information about the text currently
1029 typedef struct x11_selection_type x11_selection_type;
1030 struct x11_selection_type
1032 bool select; /* The selection is currently in use. */
1033 bool drawn; /* The selection is currently displayed. */
1034 term_type *t; /* The window where the selection is found. */
1035 co_ord init; /* The starting co-ordinates. */
1036 co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1037 co_ord old; /* The previous end co-ordinates. */
1038 Time time; /* The time at which the selection was finalised. */
1041 static x11_selection_type s_ptr[1];
1047 static void convert_to_euc(char *buf)
1049 size_t inlen = strlen(buf);
1050 size_t outlen_orig = inlen + 1;
1051 size_t outlen = outlen_orig;
1054 iconv_t iconvd = iconv_open("EUC-JP", "UTF-8");
1057 iconv(iconvd, &inbuf, &inlen, &outbuf, &outlen);
1058 iconv_close(iconvd);
1060 size_t n = outlen_orig - outlen;
1061 memcpy(buf, tmp, n);
1067 static void send_key(const char key)
1069 // Windows ドライバと同様、自前でキューを操作する。
1070 // 逆順に term_key_push() する方法だと長い日本語を入力したときにテキストの
1073 // キーバッファが一杯なら入力を捨てる
1074 const int head_nxt = Term->key_head + 1 == Term->key_size ? 0 : Term->key_head + 1;
1075 if(head_nxt == Term->key_tail) {
1076 plog_fmt("key buffer overflow, ignoring key 0x%02X", key);
1080 Term->key_queue[Term->key_head] = key;
1081 Term->key_head = head_nxt;
1085 static void send_keys(const char* const keys)
1087 for(const char* p = keys; *p != '\0'; ++p)
1092 * Process a keypress event
1094 * Also appears in "main-xaw.c".
1096 static void react_keypress(XKeyEvent *xev)
1098 int n, mc, ms, mo, mx;
1100 XKeyEvent *ev = (XKeyEvent*)(xev);
1106 int valid_keysym = TRUE;
1110 if(Focuswin && Focuswin->xic){
1112 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1113 if(status == XBufferOverflow){
1114 printf("Input is too long, and dropped\n");
1117 if(status != XLookupKeySym && status != XLookupBoth){
1118 valid_keysym = FALSE;
1121 n = XLookupString(ev, buf, 125, &ks, NULL);
1124 n = XLookupString(ev, buf, 125, &ks, NULL);
1130 if(!valid_keysym) { /* XIMからの入力時のみ FALSE になる */
1131 convert_to_euc(buf);
1137 if (IsModifierKey(ks)) return;
1140 mc = (ev->state & ControlMask) ? TRUE : FALSE;
1141 ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1142 mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1143 mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1144 if (n && !mo && !mx && !IsSpecialKey(ks))
1184 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1185 mc ? "N" : "", ms ? "S" : "",
1186 mo ? "O" : "", mx ? "M" : "",
1187 (unsigned long)(ks), 13);
1191 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1192 mc ? "N" : "", ms ? "S" : "",
1193 mo ? "O" : "", mx ? "M" : "",
1199 if (n && (macro_find_exact(msg) < 0))
1201 macro_add(msg, buf);
1206 * Find the square a particular pixel is part of.
1208 static void pixel_to_square(int * const x, int * const y,
1209 const int ox, const int oy)
1211 (*x) = (ox - Infowin->ox) / Infofnt->wid;
1212 (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1216 * Find the pixel at the top-left corner of a square.
1218 static void square_to_pixel(int * const x, int * const y,
1219 const int ox, const int oy)
1221 (*x) = ox * Infofnt->wid + Infowin->ox;
1222 (*y) = oy * Infofnt->hgt + Infowin->oy;
1226 * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
1228 static void sort_co_ord(co_ord *min, co_ord *max,
1229 const co_ord *b, const co_ord *a)
1231 min->x = MIN(a->x, b->x);
1232 min->y = MIN(a->y, b->y);
1233 max->x = MAX(a->x, b->x);
1234 max->y = MAX(a->y, b->y);
1238 * Remove the selection by redrawing it.
1240 static void mark_selection_clear(int x1, int y1, int x2, int y2)
1242 term_redraw_section(x1,y1,x2,y2);
1246 * Select an area by drawing a grey box around it.
1247 * NB. These two functions can cause flicker as the selection is modified,
1248 * as the game redraws the entire marked section.
1250 static void mark_selection_mark(int x1, int y1, int x2, int y2)
1252 square_to_pixel(&x1, &y1, x1, y1);
1253 square_to_pixel(&x2, &y2, x2, y2);
1255 XftDrawRect(Infowin->draw, &clr[2]->fg, x1, y1, x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1257 XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
1258 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1263 * Mark a selection by drawing boxes around it (for now).
1265 static void mark_selection(void)
1268 term_type *old = Term;
1269 bool draw = s_ptr->select;
1270 bool clear = s_ptr->drawn;
1271 if (s_ptr->t != old) term_activate(s_ptr->t);
1275 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
1276 mark_selection_clear(min.x, min.y, max.x, max.y);
1280 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1281 mark_selection_mark(min.x, min.y, max.x, max.y);
1284 if (s_ptr->t != old) term_activate(old);
1286 s_ptr->old.x = s_ptr->cur.x;
1287 s_ptr->old.y = s_ptr->cur.y;
1288 s_ptr->drawn = s_ptr->select;
1292 * Forget a selection for one reason or another.
1294 static void copy_x11_release(void)
1296 s_ptr->select = FALSE;
1301 * Start to select some text on the screen.
1303 static void copy_x11_start(int x, int y)
1305 if (s_ptr->select) copy_x11_release();
1308 s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
1309 s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
1313 * Respond to movement of the mouse when selecting text.
1315 static void copy_x11_cont(int x, int y, unsigned int buttons)
1317 x = MIN(MAX(x, 0), Term->wid-1);
1318 y = MIN(MAX(y, 0), Term->hgt-1);
1319 if (~buttons & Button1Mask) return;
1320 if (s_ptr->t != Term) return;
1321 if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
1323 s_ptr->select = TRUE;
1330 * Respond to release of the left mouse button by putting the selected text in
1331 * the primary buffer.
1333 static void copy_x11_end(const Time time)
1335 if (!s_ptr->select) return;
1336 if (s_ptr->t != Term) return;
1339 XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
1340 if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
1342 s_ptr->select = FALSE;
1347 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
1350 * Set the required variable atoms at start-up to avoid errors later.
1352 static void set_atoms(void)
1354 xa_targets = XInternAtom(DPY, "TARGETS", False);
1355 xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
1356 xa_text = XInternAtom(DPY, "TEXT", False);
1357 xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
1360 static Atom request_target = 0;
1363 * Send a message to request that the PRIMARY buffer be sent here.
1365 static void paste_x11_request(Atom target, const Time time)
1367 Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1368 if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
1371 /* bell("No selection found."); */
1375 request_target = target;
1376 XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
1380 * Add the contents of the PRIMARY buffer to the input queue.
1382 * Hack - This doesn't use the "time" of the event, and so accepts anything a
1383 * client tries to send it.
1385 static void paste_x11_accept(const XSelectionEvent *ptr)
1388 const long offset = 0;
1389 const long length = 32000;
1390 XTextProperty xtextproperty;
1392 Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1393 if (ptr->property == None)
1395 if (request_target == xa_compound_text)
1397 paste_x11_request(XA_STRING, ptr->time);
1402 plog("Paste failure (remote client could not send).");
1408 if (ptr->selection != XA_PRIMARY)
1410 plog("Paste failure (remote client did not send primary selection).");
1414 if (ptr->target != request_target)
1416 plog("Paste failure (selection in unknown format).");
1420 if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
1421 length, TRUE, request_target,
1422 &xtextproperty.encoding,
1423 &xtextproperty.format,
1424 &xtextproperty.nitems,
1426 &xtextproperty.value)
1432 if (request_target == xa_compound_text)
1437 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
1443 for (i = 0; i < count; i++)
1445 err = type_string(list[i], 0);
1449 XFreeStringList(list);
1454 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
1457 XFree(xtextproperty.value);
1460 plog("Paste failure (too much text selected).");
1465 * Add a character to a string in preparation for sending it to another
1466 * client as a STRING.
1467 * This doesn't change anything, as clients tend not to have difficulty in
1468 * receiving this format (although the standard specifies a restricted set).
1469 * Strings do not have a colour.
1471 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
1481 if (rq->time < s_ptr->time) return FALSE;
1483 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1484 if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
1489 XDeleteProperty(DPY, rq->requestor, rq->property);
1491 for (n = 0, y = 0; y < Term->hgt; y++)
1496 if (y < min.y) continue;
1497 if (y > max.y) break;
1499 for (l = 0, x = 0; x < Term->wid; x++)
1502 if (x > max.x) break;
1504 term_what(x, y, &a, &c);
1505 if (1 == kanji) kanji = 2;
1506 else if (iskanji(c)) kanji = 1;
1509 if (x < min.x) continue;
1512 * A single kanji character was divided in two...
1513 * Delete the garbage.
1515 if ((2 == kanji && x == min.x) ||
1516 (1 == kanji && x == max.x))
1519 if (x > max.x) break;
1520 if (x < min.x) continue;
1522 term_what(x, y, &a, &c);
1529 while (buf[l-1] == ' ') l--;
1538 list[n++] = (char *)string_make(buf);
1542 if (rq->target == XA_STRING)
1544 for (n = 0; list[n]; n++)
1546 XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
1547 PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
1550 else if (rq->target == xa_text ||
1551 rq->target == xa_compound_text)
1553 XTextProperty text_prop;
1554 XICCEncodingStyle style;
1556 if (rq->target == xa_text)
1557 style = XStdICCTextStyle;
1559 style = XCompoundTextStyle;
1562 XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
1564 XChangeProperty(DPY,
1572 XFree(text_prop.value);
1576 for (n = 0; list[n]; n++)
1578 string_free(list[n]);
1585 * Send some text requested by another X client.
1587 static void paste_x11_send(XSelectionRequestEvent *rq)
1590 XSelectionEvent *ptr = &(event.xselection);
1592 ptr->type = SelectionNotify;
1593 ptr->property = rq->property;
1594 ptr->display = rq->display;
1595 ptr->requestor = rq->requestor;
1596 ptr->selection = rq->selection;
1597 ptr->target = rq->target;
1598 ptr->time = rq->time;
1601 * Paste the appropriate information for each target type.
1602 * Note that this currently rejects MULTIPLE targets.
1605 if (rq->target == XA_STRING ||
1606 rq->target == xa_text ||
1607 rq->target == xa_compound_text)
1609 if (!paste_x11_send_text(rq))
1610 ptr->property = None;
1612 else if (rq->target == xa_targets)
1614 Atom target_list[4];
1615 target_list[0] = XA_STRING;
1616 target_list[1] = xa_text;
1617 target_list[2] = xa_compound_text;
1618 target_list[3] = xa_targets;
1619 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1620 (8 * sizeof(target_list[0])), PropModeReplace,
1621 (unsigned char *)target_list,
1622 (sizeof(target_list) / sizeof(target_list[0])));
1624 else if (rq->target == xa_timestamp)
1626 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1627 (8 * sizeof(Time)), PropModeReplace,
1628 (unsigned char *)s_ptr->time, 1);
1632 ptr->property = None;
1635 XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
1639 * Handle various events conditional on presses of a mouse button.
1641 static void handle_button(Time time, int x, int y, int button, bool press)
1643 pixel_to_square(&x, &y, x, y);
1645 if (press && button == 1) copy_x11_start(x, y);
1646 if (!press && button == 1) copy_x11_end(time);
1647 if (!press && button == 2) paste_x11_request(xa_compound_text, time);
1653 static errr CheckEvent(bool wait)
1655 term_data *old_td = (term_data*)(Term->data);
1657 XEvent xev_body, *xev = &xev_body;
1659 term_data *td = NULL;
1660 infowin *iwin = NULL;
1669 if (!wait && !XPending(Metadpy->dpy)) return (1);
1671 if (s_ptr->select && !s_ptr->drawn) mark_selection();
1673 XNextEvent(Metadpy->dpy, xev);
1676 } while (XFilterEvent(xev, xev->xany.window));
1679 if (xev->type == MappingNotify)
1681 XRefreshKeyboardMapping(&xev->xmapping);
1685 for (i = 0; i < MAX_TERM_DATA; i++)
1687 if (!data[i].win) continue;
1688 if (xev->xany.window == data[i].win->win)
1696 if (!td || !iwin) return (0);
1698 term_activate(&td->t);
1705 bool press = (xev->type == ButtonPress);
1706 int x = xev->xbutton.x;
1707 int y = xev->xbutton.y;
1709 if (xev->xbutton.button == Button1) z = 1;
1710 else if (xev->xbutton.button == Button2) z = 2;
1711 else if (xev->xbutton.button == Button3) z = 3;
1712 else if (xev->xbutton.button == Button4) z = 4;
1713 else if (xev->xbutton.button == Button5) z = 5;
1716 handle_button(xev->xbutton.time, x, y, z, press);
1726 int x = xev->xmotion.x;
1727 int y = xev->xmotion.y;
1728 unsigned int z = xev->xmotion.state;
1729 pixel_to_square(&x, &y, x, y);
1730 copy_x11_cont(x, y, z);
1733 case SelectionNotify:
1735 paste_x11_accept(&(xev->xselection));
1738 case SelectionRequest:
1740 paste_x11_send(&(xev->xselectionrequest));
1743 case SelectionClear:
1745 s_ptr->select = FALSE;
1755 term_activate(&old_td->t);
1756 react_keypress(&(xev->xkey));
1762 x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
1763 x2 = (xev->xexpose.x + xev->xexpose.width -
1764 Infowin->ox)/Infofnt->wid;
1766 y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
1767 y2 = (xev->xexpose.y + xev->xexpose.height -
1768 Infowin->oy)/Infofnt->hgt;
1770 term_redraw_section(x1, y1, x2, y2);
1775 Infowin->mapped = 1;
1776 Term->mapped_flag = TRUE;
1781 Infowin->mapped = 0;
1782 Term->mapped_flag = FALSE;
1785 case ConfigureNotify:
1787 int cols, rows, wid, hgt;
1788 int ox = Infowin->ox;
1789 int oy = Infowin->oy;
1790 Infowin->x = xev->xconfigure.x;
1791 Infowin->y = xev->xconfigure.y;
1792 Infowin->w = xev->xconfigure.width;
1793 Infowin->h = xev->xconfigure.height;
1794 cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
1795 rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
1796 if (cols < 1) cols = 1;
1797 if (rows < 1) rows = 1;
1801 if (cols < 80) cols = 80;
1802 if (rows < 24) rows = 24;
1805 wid = cols * td->fnt->wid + (ox + ox);
1806 hgt = rows * td->fnt->hgt + (oy + oy);
1807 term_resize(cols, rows);
1808 if ((Infowin->w != wid) || (Infowin->h != hgt))
1810 Infowin_set(td->win);
1811 Infowin_resize(wid, hgt);
1820 XSetICFocus(iwin->xic);
1829 XUnsetICFocus(iwin->xic);
1837 term_activate(&old_td->t);
1838 Infowin_set(old_td->win);
1843 * An array of sound file names
1845 static concptr sound_file[SOUND_MAX];
1848 * Check for existance of a file
1850 static bool check_file(concptr s)
1854 fff = fopen(s, "r");
1855 if (!fff) return (FALSE);
1864 static void init_sound(void)
1869 char dir_xtra_sound[1024];
1870 path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
1871 for (i = 1; i < SOUND_MAX; i++)
1873 sprintf(wav, "%s.wav", angband_sound_name[i]);
1874 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
1875 if (check_file(buf)) sound_file[i] = string_make(buf);
1883 * Hack -- make a sound
1885 static errr Term_xtra_x11_sound(int v)
1888 if (!use_sound) return (1);
1889 if ((v < 0) || (v >= SOUND_MAX)) return (1);
1890 if (!sound_file[v]) return (1);
1892 sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
1893 return (system(buf) < 0);
1898 * Handle "activation" of a term
1900 static errr Term_xtra_x11_level(int v)
1902 term_data *td = (term_data*)(Term->data);
1905 Infowin_set(td->win);
1906 Infofnt_set(td->fnt);
1915 static errr Term_xtra_x11_react(void)
1921 for (i = 0; i < 256; i++)
1923 if ((color_table[i][0] != angband_color_table[i][0]) ||
1924 (color_table[i][1] != angband_color_table[i][1]) ||
1925 (color_table[i][2] != angband_color_table[i][2]) ||
1926 (color_table[i][3] != angband_color_table[i][3]))
1929 color_table[i][0] = angband_color_table[i][0];
1930 color_table[i][1] = angband_color_table[i][1];
1931 color_table[i][2] = angband_color_table[i][2];
1932 color_table[i][3] = angband_color_table[i][3];
1933 pixel = create_pixel(Metadpy->dpy,
1937 Infoclr_set(clr[i]);
1938 Infoclr_change_fg(pixel);
1947 * Handle a "special request"
1949 static errr Term_xtra_x11(int n, int v)
1953 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
1954 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
1956 case TERM_XTRA_FRESH: Metadpy_update(1, 1, 0); return (0);
1958 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
1960 case TERM_XTRA_BORED: return (CheckEvent(0));
1961 case TERM_XTRA_EVENT: return (CheckEvent(v));
1962 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
1963 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
1964 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
1965 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
1966 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
1973 * Draw the cursor as an inverted rectangle.
1975 * Consider a rectangular outline like "main-mac.c". XXX XXX
1977 static errr Term_curs_x11(int x, int y)
1982 XftDrawRect(Infowin->draw, &xor->fg,
1983 x * Infofnt->wid + Infowin->ox,
1984 y * Infofnt->hgt + Infowin->oy,
1985 Infofnt->wid - 1, Infofnt->hgt - 1);
1986 XftDrawRect(Infowin->draw, &xor->fg,
1987 x * Infofnt->wid + Infowin->ox + 1,
1988 y * Infofnt->hgt + Infowin->oy + 1,
1989 Infofnt->wid - 3, Infofnt->hgt - 3);
1991 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
1992 x * Infofnt->wid + Infowin->ox,
1993 y * Infofnt->hgt + Infowin->oy,
1994 Infofnt->wid - 1, Infofnt->hgt - 1);
1995 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
1996 x * Infofnt->wid + Infowin->ox + 1,
1997 y * Infofnt->hgt + Infowin->oy + 1,
1998 Infofnt->wid - 3, Infofnt->hgt - 3);
2004 Infofnt_text_non(x, y, " ", 1);
2012 * Draw the double width cursor
2014 static errr Term_bigcurs_x11(int x, int y)
2019 XftDrawRect(Infowin->draw, &xor->fg,
2020 x * Infofnt->wid + Infowin->ox,
2021 y * Infofnt->hgt + Infowin->oy,
2022 Infofnt->twid - 1, Infofnt->hgt - 1);
2023 XftDrawRect(Infowin->draw, &xor->fg,
2024 x * Infofnt->wid + Infowin->ox + 1,
2025 y * Infofnt->hgt + Infowin->oy + 1,
2026 Infofnt->twid - 3, Infofnt->hgt - 3);
2028 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2029 x * Infofnt->wid + Infowin->ox,
2030 y * Infofnt->hgt + Infowin->oy,
2031 Infofnt->twid - 1, Infofnt->hgt - 1);
2032 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2033 x * Infofnt->wid + Infowin->ox + 1,
2034 y * Infofnt->hgt + Infowin->oy + 1,
2035 Infofnt->twid - 3, Infofnt->hgt - 3);
2041 Infofnt_text_non(x, y, " ", 2);
2048 * Erase some characters.
2050 static errr Term_wipe_x11(int x, int y, int n)
2052 Infoclr_set(clr[TERM_DARK]);
2053 Infofnt_text_non(x, y, "", n);
2054 s_ptr->drawn = FALSE;
2059 * Draw some textual characters.
2061 static errr Term_text_x11(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
2063 Infoclr_set(clr[a]);
2064 Infofnt_text_std(x, y, s, n);
2065 s_ptr->drawn = FALSE;
2071 * Draw some graphical characters.
2073 static errr Term_pict_x11(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, const char *cp, const TERM_COLOR *tap, const char *tcp)
2086 unsigned long pixel, blank;
2088 term_data *td = (term_data*)(Term->data);
2095 for (i = 0; i < n; ++i, x += td->fnt->wid)
2099 x1 = (c&0x7F) * td->fnt->twid;
2100 y1 = (a&0x7F) * td->fnt->hgt;
2101 if (td->tiles->width < x1 + td->fnt->wid ||
2102 td->tiles->height < y1 + td->fnt->hgt)
2104 XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc, x, y, td->fnt->twid, td->fnt->hgt);
2111 x2 = (tc&0x7F) * td->fnt->twid;
2112 y2 = (ta&0x7F) * td->fnt->hgt;
2114 if (((x1 == x2) && (y1 == y2)) ||
2115 !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
2116 td->tiles->width < x2 + td->fnt->wid ||
2117 td->tiles->height < y2 + td->fnt->hgt)
2119 XPutImage(Metadpy->dpy, td->win->win,
2124 td->fnt->twid, td->fnt->hgt);
2128 blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
2129 for (k = 0; k < td->fnt->twid; k++)
2131 for (l = 0; l < td->fnt->hgt; l++)
2133 if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
2135 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
2138 XPutPixel(td->TmpImage, k, l, pixel);
2142 XPutImage(Metadpy->dpy, td->win->win,
2146 td->fnt->twid, td->fnt->hgt);
2150 s_ptr->drawn = FALSE;
2156 static void IMDestroyCallback(XIM, XPointer, XPointer);
2159 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
2162 XIMCallback ximcallback;
2163 XIMStyles *xim_styles = NULL;
2169 xim = XOpenIM(display, NULL, NULL, NULL);
2171 printf("can't open IM\n");
2175 ximcallback.callback = IMDestroyCallback;
2176 ximcallback.client_data = NULL;
2177 XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
2178 XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
2179 for (i = 0; i < xim_styles->count_styles; i++){
2180 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
2182 if(i >= xim_styles->count_styles){
2183 printf("Sorry, your IM does not support 'Root' preedit style...\n");
2191 for (i = 0; i < MAX_TERM_DATA; i++)
2193 infowin *iwin = data[i].win;
2194 if (!iwin) continue;
2195 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
2198 printf("Can't create input context for Term%d\n", i);
2202 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL)
2204 iwin->xic_mask = 0L;
2207 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
2213 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
2219 if (call_data == NULL){
2220 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
2223 for(i = 0; i < MAX_TERM_DATA; i++)
2225 infowin *iwin = data[i].win;
2228 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
2229 iwin->xic_mask = 0L;
2234 Metadpy->xim = NULL;
2238 static char force_lower(char a)
2240 return ((isupper((a))) ? tolower((a)) : (a));
2244 * Initialize a term_data
2246 static errr term_data_init(term_data *td, int i)
2248 term_type *t = &td->t;
2250 concptr name = angband_term_name[i];
2280 sprintf(buf, "ANGBAND_X11_FONT_%d", i);
2282 if (!font) font = getenv("ANGBAND_X11_FONT");
2290 font = DEFAULT_X11_FONT_0;
2295 font = DEFAULT_X11_FONT_1;
2300 font = DEFAULT_X11_FONT_2;
2305 font = DEFAULT_X11_FONT_3;
2310 font = DEFAULT_X11_FONT_4;
2315 font = DEFAULT_X11_FONT_5;
2320 font = DEFAULT_X11_FONT_6;
2325 font = DEFAULT_X11_FONT_7;
2330 font = DEFAULT_X11_FONT;
2335 sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
2337 x = (str != NULL) ? atoi(str) : -1;
2339 sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
2341 y = (str != NULL) ? atoi(str) : -1;
2343 sprintf(buf, "ANGBAND_X11_COLS_%d", i);
2345 val = (str != NULL) ? atoi(str) : -1;
2346 if (val > 0) cols = val;
2348 sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
2350 val = (str != NULL) ? atoi(str) : -1;
2351 if (val > 0) rows = val;
2355 if (cols < 80) cols = 80;
2356 if (rows < 24) rows = 24;
2359 sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
2361 val = (str != NULL) ? atoi(str) : -1;
2362 if (val > 0) ox = val;
2364 sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
2366 val = (str != NULL) ? atoi(str) : -1;
2367 if (val > 0) oy = val;
2369 MAKE(td->fnt, infofnt);
2370 Infofnt_set(td->fnt);
2371 Infofnt_init_data(font);
2373 num = ((i == 0) ? 1024 : 16);
2374 wid = cols * td->fnt->wid + (ox + ox);
2375 hgt = rows * td->fnt->hgt + (oy + oy);
2376 MAKE(td->win, infowin);
2377 Infowin_set(td->win);
2378 Infowin_init_top(x, y, wid, hgt, 0,
2379 Metadpy->fg, Metadpy->bg);
2381 #if defined(USE_XIM)
2382 Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
2384 Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
2387 Infowin_set_name(name);
2390 ch = XAllocClassHint();
2392 if (ch == NULL) quit("XAllocClassHint failed");
2394 strcpy(res_name, name);
2395 res_name[0] = force_lower(res_name[0]);
2396 ch->res_name = res_name;
2398 strcpy(res_class, "Angband");
2399 ch->res_class = res_class;
2401 XSetClassHint(Metadpy->dpy, Infowin->win, ch);
2402 sh = XAllocSizeHints();
2403 if (sh == NULL) quit("XAllocSizeHints failed");
2407 sh->flags = PMinSize | PMaxSize;
2408 sh->min_width = 80 * td->fnt->wid + (ox + ox);
2409 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
2410 sh->max_width = 255 * td->fnt->wid + (ox + ox);
2411 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
2415 sh->flags = PMinSize | PMaxSize;
2416 sh->min_width = td->fnt->wid + (ox + ox);
2417 sh->min_height = td->fnt->hgt + (oy + oy);
2418 sh->max_width = 256 * td->fnt->wid + (ox + ox);
2419 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
2422 sh->flags |= PResizeInc;
2423 sh->width_inc = td->fnt->wid;
2424 sh->height_inc = td->fnt->hgt;
2425 sh->flags |= PBaseSize;
2426 sh->base_width = (ox + ox);
2427 sh->base_height = (oy + oy);
2428 XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
2432 wh = XAllocWMHints();
2433 if(wh == NULL) quit("XAllocWMHints failed");
2434 wh->flags = InputHint;
2436 XSetWMHints(Metadpy->dpy, Infowin->win, wh);
2439 if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
2441 term_init(t, cols, rows, num);
2442 t->soft_cursor = TRUE;
2443 t->attr_blank = TERM_WHITE;
2444 t->char_blank = ' ';
2445 t->xtra_hook = Term_xtra_x11;
2446 t->curs_hook = Term_curs_x11;
2447 t->bigcurs_hook = Term_bigcurs_x11;
2448 t->wipe_hook = Term_wipe_x11;
2449 t->text_hook = Term_text_x11;
2456 * Initialization function for an "X11" module to Angband
2458 errr init_x11(int argc, char *argv[])
2461 concptr dpy_name = "";
2465 char filename[1024];
2473 for (i = 1; i < argc; i++)
2475 if (prefix(argv[i], "-d"))
2477 dpy_name = &argv[i][2];
2482 if (prefix(argv[i], "-s"))
2484 smoothRescaling = FALSE;
2488 if (prefix(argv[i], "-a"))
2490 arg_graphics = GRAPHICS_ADAM_BOLT;
2494 if (prefix(argv[i], "-o"))
2496 arg_graphics = GRAPHICS_ORIGINAL;
2501 if (prefix(argv[i], "-b"))
2503 arg_bigtile = use_bigtile = TRUE;
2507 if (prefix(argv[i], "-n"))
2509 num_term = atoi(&argv[i][2]);
2510 if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
2511 else if (num_term < 1) num_term = 1;
2515 if (prefix(argv[i], "--"))
2520 plog_fmt("Ignoring option: %s", argv[i]);
2526 setlocale(LC_ALL, "");
2528 #ifdef DEFAULT_LOCALE
2529 if(!strcmp(setlocale(LC_ALL, NULL), "C")){
2530 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
2531 setlocale(LC_ALL, DEFAULT_LOCALE);
2535 if(!strcmp(setlocale(LC_ALL, NULL), "C"))
2537 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
2540 if(!XSupportsLocale()){
2541 printf("can't support locale in X\n");
2542 setlocale(LC_ALL, "C");
2545 setlocale(LC_ALL, "C");
2548 #endif /* USE_LOCALE */
2550 if (Metadpy_init_name(dpy_name)) return (-1);
2554 Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
2555 for (i = 0; i < 256; ++i)
2558 MAKE(clr[i], infoclr);
2559 Infoclr_set(clr[i]);
2560 color_table[i][0] = angband_color_table[i][0];
2561 color_table[i][1] = angband_color_table[i][1];
2562 color_table[i][2] = angband_color_table[i][2];
2563 color_table[i][3] = angband_color_table[i][3];
2564 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
2567 pixel = create_pixel(Metadpy->dpy,
2573 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
2577 for (i = 0; i < num_term; i++)
2579 term_data *td = &data[i];
2580 term_data_init(td, i);
2581 angband_term[i] = Term;
2584 Infowin_set(data[0].win);
2586 term_activate(&data[0].t);
2591 p = XSetLocaleModifiers("");
2593 p = XSetLocaleModifiers("@im=");
2596 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
2599 if (arg_sound) init_sound();
2602 switch (arg_graphics)
2604 case GRAPHICS_ORIGINAL:
2605 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
2606 if (0 == fd_close(fd_open(filename, O_RDONLY)))
2608 use_graphics = TRUE;
2609 pict_wid = pict_hgt = 8;
2610 ANGBAND_GRAF = "old";
2613 case GRAPHICS_ADAM_BOLT:
2614 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
2615 if (0 == fd_close(fd_open(filename, O_RDONLY)))
2617 use_graphics = TRUE;
2618 pict_wid = pict_hgt = 16;
2619 ANGBAND_GRAF = "new";
2626 Display *dpy = Metadpy->dpy;
2628 tiles_raw = ReadBMP(dpy, filename);
2629 for (i = 0; i < num_term; i++)
2631 term_data *td = &data[i];
2632 term_type *t = &td->t;
2633 t->pict_hook = Term_pict_x11;
2634 t->higher_pict = TRUE;
2636 ResizeImage(dpy, tiles_raw,
2638 td->fnt->twid, td->fnt->hgt);
2641 for (i = 0; i < num_term; i++)
2643 term_data *td = &data[i];
2645 int depth = DefaultDepth(dpy, DefaultScreen(dpy));
2646 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
2649 jj = (depth - 1) >> 2;
2650 while (jj >>= 1) ii <<= 1;
2651 total = td->fnt->twid * td->fnt->hgt * ii;
2652 TmpData = (char *)malloc(total);
2653 td->TmpImage = XCreateImage(dpy,visual,depth,
2654 ZPixmap, 0, TmpData,
2655 td->fnt->twid, td->fnt->hgt, 8, 0);
2658 #endif /* ! USE_XFT */
2662 #endif /* USE_X11 */