xref: /aosp_15_r20/external/coreboot/payloads/libpayload/curses/PDCurses/x11/x11.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* Public Domain Curses */
2 
3 #include "pdcx11.h"
4 
5 RCSID("$Id: x11.c,v 1.94 2008/07/14 04:33:26 wmcbrine Exp $")
6 
7 #ifdef HAVE_DECKEYSYM_H
8 # include <DECkeysym.h>
9 #endif
10 
11 #ifdef HAVE_SUNKEYSYM_H
12 # include <Sunkeysym.h>
13 #endif
14 
15 #ifdef HAVE_XPM_H
16 # include <xpm.h>
17 #endif
18 
19 #if defined PDC_XIM
20 # include <Xlocale.h>
21 #endif
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #ifndef XPOINTER_TYPEDEFED
27 typedef char * XPointer;
28 #endif
29 
30 #ifndef MAX_PATH
31 # define MAX_PATH 256
32 #endif
33 
34 XCursesAppData xc_app_data;
35 
36 #if NeedWidePrototypes
37 # define PDC_SCROLLBAR_TYPE double
38 #else
39 # define PDC_SCROLLBAR_TYPE float
40 #endif
41 
42 #define MAX_COLORS   16             /* maximum of "normal" colors */
43 #define COLOR_CURSOR MAX_COLORS     /* color of cursor */
44 #define COLOR_BORDER MAX_COLORS + 1 /* color of border */
45 
46 #define XCURSESDISPLAY (XtDisplay(drawing))
47 #define XCURSESWIN     (XtWindow(drawing))
48 
49 /* Default icons for XCurses applications.  */
50 
51 #include "big_icon.xbm"
52 #include "little_icon.xbm"
53 
54 static void _selection_off(void);
55 static void _display_cursor(int, int, int, int);
56 static void _redraw_cursor(void);
57 static void _exit_process(int, int, char *);
58 static void _send_key_to_curses(unsigned long, MOUSE_STATUS *, bool);
59 
60 static void XCursesButton(Widget, XEvent *, String *, Cardinal *);
61 static void XCursesHandleString(Widget, XEvent *, String *, Cardinal *);
62 static void XCursesKeyPress(Widget, XEvent *, String *, Cardinal *);
63 static void XCursesPasteSelection(Widget, XButtonEvent *);
64 
65 static struct
66 {
67     KeySym keycode;
68     bool numkeypad;
69     unsigned short normal;
70     unsigned short shifted;
71     unsigned short control;
72     unsigned short alt;
73 } key_table[] =
74 {
75 /* keycode      keypad  normal       shifted       control      alt*/
76  {XK_Left,      FALSE,  KEY_LEFT,    KEY_SLEFT,    CTL_LEFT,    ALT_LEFT},
77  {XK_Right,     FALSE,  KEY_RIGHT,   KEY_SRIGHT,   CTL_RIGHT,   ALT_RIGHT},
78  {XK_Up,        FALSE,  KEY_UP,      KEY_SUP,      CTL_UP,      ALT_UP},
79  {XK_Down,      FALSE,  KEY_DOWN,    KEY_SDOWN,    CTL_DOWN,    ALT_DOWN},
80  {XK_Home,      FALSE,  KEY_HOME,    KEY_SHOME,    CTL_HOME,    ALT_HOME},
81 /* Sun Type 4 keyboard */
82  {XK_R7,        FALSE,  KEY_HOME,    KEY_SHOME,    CTL_HOME,    ALT_HOME},
83  {XK_End,       FALSE,  KEY_END,     KEY_SEND,     CTL_END,     ALT_END},
84 /* Sun Type 4 keyboard */
85  {XK_R13,       FALSE,  KEY_END,     KEY_SEND,     CTL_END,     ALT_END},
86  {XK_Prior,     FALSE,  KEY_PPAGE,   KEY_SPREVIOUS,CTL_PGUP,    ALT_PGUP},
87 /* Sun Type 4 keyboard */
88  {XK_R9,        FALSE,  KEY_PPAGE,   KEY_SPREVIOUS,CTL_PGUP,    ALT_PGUP},
89  {XK_Next,      FALSE,  KEY_NPAGE,   KEY_SNEXT,    CTL_PGDN,    ALT_PGDN},
90 /* Sun Type 4 keyboard */
91  {XK_R15,       FALSE,  KEY_NPAGE,   KEY_SNEXT,    CTL_PGDN,    ALT_PGDN},
92  {XK_Insert,    FALSE,  KEY_IC,      KEY_SIC,      CTL_INS,     ALT_INS},
93  {XK_Delete,    FALSE,  KEY_DC,      KEY_SDC,      CTL_DEL,     ALT_DEL},
94  {XK_F1,        FALSE,  KEY_F(1),    KEY_F(13),    KEY_F(25),   KEY_F(37)},
95  {XK_F2,        FALSE,  KEY_F(2),    KEY_F(14),    KEY_F(26),   KEY_F(38)},
96  {XK_F3,        FALSE,  KEY_F(3),    KEY_F(15),    KEY_F(27),   KEY_F(39)},
97  {XK_F4,        FALSE,  KEY_F(4),    KEY_F(16),    KEY_F(28),   KEY_F(40)},
98  {XK_F5,        FALSE,  KEY_F(5),    KEY_F(17),    KEY_F(29),   KEY_F(41)},
99  {XK_F6,        FALSE,  KEY_F(6),    KEY_F(18),    KEY_F(30),   KEY_F(42)},
100  {XK_F7,        FALSE,  KEY_F(7),    KEY_F(19),    KEY_F(31),   KEY_F(43)},
101  {XK_F8,        FALSE,  KEY_F(8),    KEY_F(20),    KEY_F(32),   KEY_F(44)},
102  {XK_F9,        FALSE,  KEY_F(9),    KEY_F(21),    KEY_F(33),   KEY_F(45)},
103  {XK_F10,       FALSE,  KEY_F(10),   KEY_F(22),    KEY_F(34),   KEY_F(46)},
104  {XK_F11,       FALSE,  KEY_F(11),   KEY_F(23),    KEY_F(35),   KEY_F(47)},
105  {XK_F12,       FALSE,  KEY_F(12),   KEY_F(24),    KEY_F(36),   KEY_F(48)},
106  {XK_F13,       FALSE,  KEY_F(13),   KEY_F(25),    KEY_F(37),   KEY_F(49)},
107  {XK_F14,       FALSE,  KEY_F(14),   KEY_F(26),    KEY_F(38),   KEY_F(50)},
108  {XK_F15,       FALSE,  KEY_F(15),   KEY_F(27),    KEY_F(39),   KEY_F(51)},
109  {XK_F16,       FALSE,  KEY_F(16),   KEY_F(28),    KEY_F(40),   KEY_F(52)},
110  {XK_F17,       FALSE,  KEY_F(17),   KEY_F(29),    KEY_F(41),   KEY_F(53)},
111  {XK_F18,       FALSE,  KEY_F(18),   KEY_F(30),    KEY_F(42),   KEY_F(54)},
112  {XK_F19,       FALSE,  KEY_F(19),   KEY_F(31),    KEY_F(43),   KEY_F(55)},
113  {XK_F20,       FALSE,  KEY_F(20),   KEY_F(32),    KEY_F(44),   KEY_F(56)},
114  {XK_BackSpace, FALSE,  0x08,        0x08,         CTL_BKSP,    ALT_BKSP},
115  {XK_Tab,       FALSE,  0x09,        KEY_BTAB,     CTL_TAB,     ALT_TAB},
116  {XK_Select,    FALSE,  KEY_SELECT,  KEY_SELECT,   KEY_SELECT,  KEY_SELECT},
117  {XK_Print,     FALSE,  KEY_PRINT,   KEY_SPRINT,   KEY_PRINT,   KEY_PRINT},
118  {XK_Find,      FALSE,  KEY_FIND,    KEY_SFIND,    KEY_FIND,    KEY_FIND},
119  {XK_Pause,     FALSE,  KEY_SUSPEND, KEY_SSUSPEND, KEY_SUSPEND, KEY_SUSPEND},
120  {XK_Clear,     FALSE,  KEY_CLEAR,   KEY_CLEAR,    KEY_CLEAR,   KEY_CLEAR},
121  {XK_Cancel,    FALSE,  KEY_CANCEL,  KEY_SCANCEL,  KEY_CANCEL,  KEY_CANCEL},
122  {XK_Break,     FALSE,  KEY_BREAK,   KEY_BREAK,    KEY_BREAK,   KEY_BREAK},
123  {XK_Help,      FALSE,  KEY_HELP,    KEY_SHELP,    KEY_LHELP,   KEY_HELP},
124  {XK_L4,        FALSE,  KEY_UNDO,    KEY_SUNDO,    KEY_UNDO,    KEY_UNDO},
125  {XK_L6,        FALSE,  KEY_COPY,    KEY_SCOPY,    KEY_COPY,    KEY_COPY},
126  {XK_L9,        FALSE,  KEY_FIND,    KEY_SFIND,    KEY_FIND,    KEY_FIND},
127  {XK_Menu,      FALSE,  KEY_OPTIONS, KEY_SOPTIONS, KEY_OPTIONS, KEY_OPTIONS},
128 #ifdef HAVE_SUNKEYSYM_H
129  {SunXK_F36,    FALSE,  KEY_F(41),   KEY_F(43),    KEY_F(45),   KEY_F(47)},
130  {SunXK_F37,    FALSE,  KEY_F(42),   KEY_F(44),    KEY_F(46),   KEY_F(48)},
131 #endif
132 #ifdef HAVE_DECKEYSYM_H
133  {DXK_Remove,   FALSE,  KEY_DC,      KEY_SDC,      CTL_DEL,     ALT_DEL},
134 #endif
135  {XK_Escape,    FALSE,  0x1B,        0x1B,         0x1B,        ALT_ESC},
136  {XK_KP_Enter,  TRUE,   PADENTER,    PADENTER,     CTL_PADENTER,ALT_PADENTER},
137  {XK_KP_Add,    TRUE,   PADPLUS,     '+',          CTL_PADPLUS, ALT_PADPLUS},
138  {XK_KP_Subtract,TRUE,  PADMINUS,    '-',          CTL_PADMINUS,ALT_PADMINUS},
139  {XK_KP_Multiply,TRUE,  PADSTAR,     '*',          CTL_PADSTAR, ALT_PADSTAR},
140 /* Sun Type 4 keyboard */
141  {XK_R6,        TRUE,   PADSTAR,     '*',          CTL_PADSTAR, ALT_PADSTAR},
142  {XK_KP_Divide, TRUE,   PADSLASH,    '/',          CTL_PADSLASH,ALT_PADSLASH},
143 /* Sun Type 4 keyboard */
144  {XK_R5,        TRUE,   PADSLASH,    '/',          CTL_PADSLASH,ALT_PADSLASH},
145  {XK_KP_Decimal,TRUE,   PADSTOP,     '.',          CTL_PADSTOP, ALT_PADSTOP},
146  {XK_KP_0,      TRUE,   PAD0,        '0',          CTL_PAD0,    ALT_PAD0},
147  {XK_KP_1,      TRUE,   KEY_C1,      '1',          CTL_PAD1,    ALT_PAD1},
148  {XK_KP_2,      TRUE,   KEY_C2,      '2',          CTL_PAD2,    ALT_PAD2},
149  {XK_KP_3,      TRUE,   KEY_C3,      '3',          CTL_PAD3,    ALT_PAD3},
150  {XK_KP_4,      TRUE,   KEY_B1,      '4',          CTL_PAD4,    ALT_PAD4},
151  {XK_KP_5,      TRUE,   KEY_B2,      '5',          CTL_PAD5,    ALT_PAD5},
152 /* Sun Type 4 keyboard */
153  {XK_R11,       TRUE,   KEY_B2,      '5',          CTL_PAD5,    ALT_PAD5},
154  {XK_KP_6,      TRUE,   KEY_B3,      '6',          CTL_PAD6,    ALT_PAD6},
155  {XK_KP_7,      TRUE,   KEY_A1,      '7',          CTL_PAD7,    ALT_PAD7},
156  {XK_KP_8,      TRUE,   KEY_A2,      '8',          CTL_PAD8,    ALT_PAD8},
157  {XK_KP_9,      TRUE,   KEY_A3,      '9',          CTL_PAD9,    ALT_PAD9},
158 /* the following added to support Sun Type 5 keyboards */
159  {XK_F21,       FALSE,  KEY_SUSPEND, KEY_SSUSPEND, KEY_SUSPEND, KEY_SUSPEND},
160  {XK_F22,       FALSE,  KEY_PRINT,   KEY_SPRINT,   KEY_PRINT,   KEY_PRINT},
161  {XK_F24,       TRUE,   PADMINUS,    '-',          CTL_PADMINUS,ALT_PADMINUS},
162 /* Sun Type 4 keyboard */
163  {XK_F25,       TRUE,   PADSLASH,    '/',          CTL_PADSLASH,ALT_PADSLASH},
164 /* Sun Type 4 keyboard */
165  {XK_F26,       TRUE,   PADSTAR,     '*',          CTL_PADSTAR, ALT_PADSTAR},
166  {XK_F27,       TRUE,   KEY_A1,      '7',          CTL_PAD7,    ALT_PAD7},
167  {XK_F29,       TRUE,   KEY_A3,      '9',          CTL_PAD9,    ALT_PAD9},
168  {XK_F31,       TRUE,   KEY_B2,      '5',          CTL_PAD5,    ALT_PAD5},
169  {XK_F35,       TRUE,   KEY_C3,      '3',          CTL_PAD3,    ALT_PAD3},
170 #ifdef HAVE_XK_KP_DELETE
171  {XK_KP_Delete, TRUE,   PADSTOP,     '.',          CTL_PADSTOP, ALT_PADSTOP},
172 #endif
173 #ifdef HAVE_XK_KP_INSERT
174  {XK_KP_Insert, TRUE,   PAD0,        '0',          CTL_PAD0,    ALT_PAD0},
175 #endif
176 #ifdef HAVE_XK_KP_END
177  {XK_KP_End,    TRUE,   KEY_C1,      '1',          CTL_PAD1,    ALT_PAD1},
178 #endif
179 #ifdef HAVE_XK_KP_DOWN
180  {XK_KP_Down,   TRUE,   KEY_C2,      '2',          CTL_PAD2,    ALT_PAD2},
181 #endif
182 #ifdef HAVE_XK_KP_NEXT
183  {XK_KP_Next,   TRUE,   KEY_C3,      '3',          CTL_PAD3,    ALT_PAD3},
184 #endif
185 #ifdef HAVE_XK_KP_LEFT
186  {XK_KP_Left,   TRUE,   KEY_B1,      '4',          CTL_PAD4,    ALT_PAD4},
187 #endif
188 #ifdef HAVE_XK_KP_BEGIN
189  {XK_KP_Begin,  TRUE,   KEY_B2,      '5',          CTL_PAD5,    ALT_PAD5},
190 #endif
191 #ifdef HAVE_XK_KP_RIGHT
192  {XK_KP_Right,  TRUE,   KEY_B3,      '6',          CTL_PAD6,    ALT_PAD6},
193 #endif
194 #ifdef HAVE_XK_KP_HOME
195  {XK_KP_Home,   TRUE,   KEY_A1,      '7',          CTL_PAD7,    ALT_PAD7},
196 #endif
197 #ifdef HAVE_XK_KP_UP
198  {XK_KP_Up,     TRUE,   KEY_A2,      '8',          CTL_PAD8,    ALT_PAD8},
199 #endif
200 #ifdef HAVE_XK_KP_PRIOR
201  {XK_KP_Prior,  TRUE,   KEY_A3,      '9',          CTL_PAD9,    ALT_PAD9},
202 #endif
203  {0,            0,      0,           0,            0,           0}
204 };
205 
206 #ifndef PDC_XIM
207 # include "compose.h"
208 #endif
209 
210 #define BITMAPDEPTH 1
211 
212 unsigned long pdc_key_modifiers = 0L;
213 
214 static GC normal_gc, block_cursor_gc, rect_cursor_gc, italic_gc, border_gc;
215 static int font_height, font_width, font_ascent, font_descent,
216            window_width, window_height;
217 static int resize_window_width = 0, resize_window_height = 0;
218 static char *bitmap_file = NULL;
219 #ifdef HAVE_XPM_H
220 static char *pixmap_file = NULL;
221 #endif
222 static KeySym keysym = 0;
223 
224 static int state_mask[8] =
225 {
226     ShiftMask,
227     LockMask,
228     ControlMask,
229     Mod1Mask,
230     Mod2Mask,
231     Mod3Mask,
232     Mod4Mask,
233     Mod5Mask
234 };
235 
236 static Atom wm_atom[2];
237 static String class_name = "XCurses";
238 static XtAppContext app_context;
239 static Widget topLevel, drawing, scrollBox, scrollVert, scrollHoriz;
240 static int received_map_notify = 0;
241 static bool mouse_selection = FALSE;
242 static chtype *tmpsel = NULL;
243 static unsigned long tmpsel_length = 0;
244 static int selection_start_x = 0, selection_start_y = 0,
245            selection_end_x = 0, selection_end_y = 0;
246 static Pixmap icon_bitmap;
247 #ifdef HAVE_XPM_H
248 static Pixmap icon_pixmap;
249 static Pixmap icon_pixmap_mask;
250 #endif
251 static bool visible_cursor = FALSE;
252 static bool window_entered = TRUE;
253 static char *program_name;
254 
255 /* Macros just for app_resources */
256 
257 #ifdef PDC_WIDE
258 # define DEFFONT "-misc-fixed-medium-r-normal--20-200-75-75-c-100-iso10646-1"
259 #else
260 # define DEFFONT "7x13"
261 #endif
262 
263 #define APPDATAOFF(n) XtOffsetOf(XCursesAppData, n)
264 
265 #define RINT(name1, name2, value) { \
266                 #name1, #name2, XtRInt, \
267                 sizeof(int), APPDATAOFF(name1), XtRImmediate, \
268                 (XtPointer)value \
269         }
270 
271 #define RPIXEL(name1, name2, value) { \
272                 #name1, #name2, XtRPixel, \
273                 sizeof(Pixel), APPDATAOFF(name1), XtRString, \
274                 (XtPointer)#value \
275         }
276 
277 #define RCOLOR(name, value) RPIXEL(color##name, Color##name, value)
278 
279 #define RSTRINGP(name1, name2, param) { \
280                 #name1, #name2, XtRString, \
281                 MAX_PATH, APPDATAOFF(name1), XtRString, (XtPointer)param \
282         }
283 
284 #define RSTRING(name1, name2) RSTRINGP(name1, name2, "")
285 
286 #define RFONT(name1, name2, value) { \
287                 #name1, #name2, XtRFontStruct, \
288                 sizeof(XFontStruct), APPDATAOFF(name1), XtRString, \
289                 (XtPointer)value \
290         }
291 
292 #define RCURSOR(name1, name2, value) { \
293                 #name1, #name2, XtRCursor, \
294                 sizeof(Cursor), APPDATAOFF(name1), XtRString, \
295                 (XtPointer)#value \
296         }
297 
298 static XtResource app_resources[] =
299 {
300     RINT(lines, Lines, 24),
301     RINT(cols, Cols, 80),
302 
303     RPIXEL(cursorColor, CursorColor, Red),
304 
305     RCOLOR(Black, Black),
306     RCOLOR(Red, red3),
307     RCOLOR(Green, green3),
308     RCOLOR(Yellow, yellow3),
309     RCOLOR(Blue, blue3),
310     RCOLOR(Magenta, magenta3),
311     RCOLOR(Cyan, cyan3),
312     RCOLOR(White, Grey),
313 
314     RCOLOR(BoldBlack, grey40),
315     RCOLOR(BoldRed, red1),
316     RCOLOR(BoldGreen, green1),
317     RCOLOR(BoldYellow, yellow1),
318     RCOLOR(BoldBlue, blue1),
319     RCOLOR(BoldMagenta, magenta1),
320     RCOLOR(BoldCyan, cyan1),
321     RCOLOR(BoldWhite, White),
322 
323     RFONT(normalFont, NormalFont, DEFFONT),
324     RFONT(italicFont, ItalicFont, DEFFONT),
325 
326     RSTRING(bitmap, Bitmap),
327 #ifdef HAVE_XPM_H
328     RSTRING(pixmap, Pixmap),
329 #endif
330     RSTRINGP(composeKey, ComposeKey, "Multi_key"),
331 
332     RCURSOR(pointer, Pointer, xterm),
333 
334     RPIXEL(pointerForeColor, PointerForeColor, Black),
335     RPIXEL(pointerBackColor, PointerBackColor, White),
336 
337     RINT(shmmin, Shmmin, 0),
338     RINT(borderWidth, BorderWidth, 0),
339 
340     RPIXEL(borderColor, BorderColor, Black),
341 
342     RINT(doubleClickPeriod, DoubleClickPeriod, (PDC_CLICK_PERIOD * 2)),
343     RINT(clickPeriod, ClickPeriod, PDC_CLICK_PERIOD),
344     RINT(scrollbarWidth, ScrollbarWidth, 15),
345     RINT(cursorBlinkRate, CursorBlinkRate, 0),
346 
347     RSTRING(textCursor, TextCursor)
348 };
349 
350 #undef RCURSOR
351 #undef RFONT
352 #undef RSTRING
353 #undef RCOLOR
354 #undef RPIXEL
355 #undef RINT
356 #undef APPDATAOFF
357 #undef DEFFONT
358 
359 /* Macros for options */
360 
361 #define COPT(name) {"-" #name, "*" #name, XrmoptionSepArg, NULL}
362 #define CCOLOR(name) COPT(color##name)
363 
364 static XrmOptionDescRec options[] =
365 {
366     COPT(lines), COPT(cols), COPT(normalFont), COPT(italicFont),
367     COPT(bitmap),
368 #ifdef HAVE_XPM_H
369     COPT(pixmap),
370 #endif
371     COPT(pointer), COPT(shmmin), COPT(composeKey), COPT(clickPeriod),
372     COPT(doubleClickPeriod), COPT(scrollbarWidth),
373     COPT(pointerForeColor), COPT(pointerBackColor),
374     COPT(cursorBlinkRate), COPT(cursorColor), COPT(textCursor),
375 
376     CCOLOR(Black), CCOLOR(Red), CCOLOR(Green), CCOLOR(Yellow),
377     CCOLOR(Blue), CCOLOR(Magenta), CCOLOR(Cyan), CCOLOR(White),
378 
379     CCOLOR(BoldBlack), CCOLOR(BoldRed), CCOLOR(BoldGreen),
380     CCOLOR(BoldYellow), CCOLOR(BoldBlue), CCOLOR(BoldMagenta),
381     CCOLOR(BoldCyan), CCOLOR(BoldWhite)
382 };
383 
384 #undef CCOLOR
385 #undef COPT
386 
387 static XtActionsRec action_table[] =
388 {
389     {"XCursesButton",         (XtActionProc)XCursesButton},
390     {"XCursesKeyPress",       (XtActionProc)XCursesKeyPress},
391     {"XCursesPasteSelection", (XtActionProc)XCursesPasteSelection},
392     {"string",                (XtActionProc)XCursesHandleString}
393 };
394 
395 static bool after_first_curses_request = FALSE;
396 static Pixel colors[MAX_COLORS + 2];
397 static bool vertical_cursor = FALSE;
398 
399 #ifdef PDC_XIM
400 static XIM Xim = NULL;
401 static XIC Xic = NULL;
402 #endif
403 
404 static const char *default_translations =
405 {
406     "<Key>: XCursesKeyPress() \n" \
407     "<KeyUp>: XCursesKeyPress() \n" \
408     "<BtnDown>: XCursesButton() \n" \
409     "<BtnUp>: XCursesButton() \n" \
410     "<BtnMotion>: XCursesButton()"
411 };
412 
_to_utf8(char * outcode,chtype code)413 static int _to_utf8(char *outcode, chtype code)
414 {
415 #ifdef PDC_WIDE
416     if (code & A_ALTCHARSET && !(code & 0xff80))
417         code = acs_map[code & 0x7f];
418 #endif
419     code &= A_CHARTEXT;
420 
421     if (code < 0x80)
422     {
423         outcode[0] = code;
424         return 1;
425     }
426     else
427         if (code < 0x800)
428         {
429             outcode[0] = ((code & 0x07c0) >> 6) | 0xc0;
430             outcode[1] = (code & 0x003f) | 0x80;
431             return 2;
432         }
433         else
434         {
435             outcode[0] = ((code & 0xf000) >> 12) | 0xe0;
436             outcode[1] = ((code & 0x0fc0) >> 6) | 0x80;
437             outcode[2] = (code & 0x003f) | 0x80;
438             return 3;
439         }
440 }
441 
_from_utf8(wchar_t * pwc,const char * s,size_t n)442 static int _from_utf8(wchar_t *pwc, const char *s, size_t n)
443 {
444     wchar_t key;
445     int i = -1;
446     const unsigned char *string;
447 
448     if (!s || (n < 1))
449         return -1;
450 
451     if (!*s)
452         return 0;
453 
454     string = (const unsigned char *)s;
455 
456     key = string[0];
457 
458     /* Simplistic UTF-8 decoder -- only does the BMP, minimal validation */
459 
460     if (key & 0x80)
461     {
462         if ((key & 0xe0) == 0xc0)
463         {
464             if (1 < n)
465             {
466                 key = ((key & 0x1f) << 6) | (string[1] & 0x3f);
467                 i = 2;
468             }
469         }
470         else if ((key & 0xe0) == 0xe0)
471         {
472             if (2 < n)
473             {
474                 key = ((key & 0x0f) << 12) |
475                       ((string[1] & 0x3f) << 6) | (string[2] & 0x3f);
476                 i = 3;
477             }
478         }
479     }
480     else
481         i = 1;
482 
483     if (i)
484         *pwc = key;
485 
486     return i;
487 }
488 
489 #ifndef X_HAVE_UTF8_STRING
XA_UTF8_STRING(Display * dpy)490 static Atom XA_UTF8_STRING(Display *dpy)
491 {
492     static AtomPtr p = NULL;
493 
494     if (!p)
495         p = XmuMakeAtom("UTF8_STRING");
496 
497     return XmuInternAtom(dpy, p);
498 }
499 #endif
500 
XCursesSetSignal(int signo,signal_handler action)501 signal_handler XCursesSetSignal(int signo, signal_handler action)
502 {
503 #if defined(SA_INTERRUPT) || defined(SA_RESTART)
504     struct sigaction sigact, osigact;
505 
506     sigact.sa_handler = action;
507 
508     sigact.sa_flags =
509 # ifdef SA_INTERRUPT
510 #  ifdef SA_RESTART
511         SA_INTERRUPT | SA_RESTART;
512 #  else
513         SA_INTERRUPT;
514 #  endif
515 # else  /* must be SA_RESTART */
516         SA_RESTART;
517 # endif
518     sigemptyset(&sigact.sa_mask);
519 
520     if (sigaction(signo, &sigact, &osigact))
521         return SIG_ERR;
522 
523     return osigact.sa_handler;
524 
525 #else   /* not SA_INTERRUPT or SA_RESTART, use plain signal */
526     return signal(signo, action);
527 #endif
528 }
529 
XCursesSigwinchHandler(int signo)530 RETSIGTYPE XCursesSigwinchHandler(int signo)
531 {
532     PDC_LOG(("%s:XCursesSigwinchHandler() - called: SIGNO: %d\n",
533              XCLOGMSG, signo));
534 
535     /* Patch by: Georg Fuchs, [email protected]
536        02-Feb-1999 */
537 
538     SP->resized += 1;
539 
540     /* Always trap SIGWINCH if the C library supports SIGWINCH */
541 
542 #ifdef SIGWINCH
543     XCursesSetSignal(SIGWINCH, XCursesSigwinchHandler);
544 #endif
545 }
546 
547 /* Convert character positions x and y to pixel positions, stored in
548    xpos and ypos */
549 
_make_xy(int x,int y,int * xpos,int * ypos)550 static void _make_xy(int x, int y, int *xpos, int *ypos)
551 {
552     *xpos = (x * font_width) + xc_app_data.borderWidth;
553     *ypos = xc_app_data.normalFont->ascent + (y * font_height) +
554             xc_app_data.borderWidth;
555 }
556 
557 /* Output a block of characters with common attributes */
558 
_new_packet(chtype attr,bool rev,int len,int col,int row,XChar2b * text)559 static int _new_packet(chtype attr, bool rev, int len, int col, int row,
560 #ifdef PDC_WIDE
561                        XChar2b *text)
562 #else
563                        char *text)
564 #endif
565 {
566     GC gc;
567     int xpos, ypos;
568     short fore, back;
569 
570     PDC_pair_content(PAIR_NUMBER(attr), &fore, &back);
571 
572 #ifdef PDC_WIDE
573     text[len].byte1 = text[len].byte2 = 0;
574 #else
575     text[len] = '\0';
576 #endif
577 
578     /* Specify the color table offsets */
579 
580     fore |= (attr & A_BOLD) ? 8 : 0;
581     back |= (attr & A_BLINK) ? 8 : 0;
582 
583     /* Reverse flag = highlighted selection XOR A_REVERSE set */
584 
585     rev ^= !!(attr & A_REVERSE);
586 
587     /* Determine which GC to use - normal or italic */
588 
589     gc = (attr & A_ITALIC) ? italic_gc : normal_gc;
590 
591     /* Draw it */
592 
593     XSetForeground(XCURSESDISPLAY, gc, colors[rev ? back : fore]);
594     XSetBackground(XCURSESDISPLAY, gc, colors[rev ? fore : back]);
595 
596     _make_xy(col, row, &xpos, &ypos);
597 
598 #ifdef PDC_WIDE
599     XDrawImageString16(
600 #else
601     XDrawImageString(
602 #endif
603                      XCURSESDISPLAY, XCURSESWIN, gc, xpos, ypos, text, len);
604 
605     /* Underline, etc. */
606 
607     if (attr & (A_LEFTLINE|A_RIGHTLINE|A_UNDERLINE))
608     {
609         int k;
610 
611         if (SP->line_color != -1)
612             XSetForeground(XCURSESDISPLAY, gc, colors[SP->line_color]);
613 
614         if (attr & A_UNDERLINE)     /* UNDER */
615             XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc,
616                       xpos, ypos + 1, xpos + font_width * len, ypos + 1);
617 
618         if (attr & A_LEFTLINE)      /* LEFT */
619             for (k = 0; k < len; k++)
620             {
621                 int x = xpos + font_width * k - 1;
622                 XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc,
623                           x, ypos - font_ascent, x, ypos + font_descent);
624             }
625 
626         if (attr & A_RIGHTLINE)     /* RIGHT */
627             for (k = 0; k < len; k++)
628             {
629                 int x = xpos + font_width * (k + 1) - 1;
630                 XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc,
631                           x, ypos - font_ascent, x, ypos + font_descent);
632             }
633     }
634 
635     PDC_LOG(("%s:_new_packet() - row: %d col: %d "
636              "num_cols: %d fore: %d back: %d text:<%s>\n",
637              XCLOGMSG, row, col, len, fore, back, text));
638 
639     return OK;
640 }
641 
642 /* The core display routine -- update one line of text */
643 
_display_text(const chtype * ch,int row,int col,int num_cols,bool highlight)644 static int _display_text(const chtype *ch, int row, int col,
645                          int num_cols, bool highlight)
646 {
647 #ifdef PDC_WIDE
648     XChar2b text[513];
649 #else
650     char text[513];
651 #endif
652     chtype old_attr, attr;
653     int i, j;
654 
655     PDC_LOG(("%s:_display_text() - called: row: %d col: %d "
656              "num_cols: %d\n", XCLOGMSG, row, col, num_cols));
657 
658     if (!num_cols)
659         return OK;
660 
661     old_attr = *ch & A_ATTRIBUTES;
662 
663     for (i = 0, j = 0; j < num_cols; j++)
664     {
665         chtype curr = ch[j];
666 
667         attr = curr & A_ATTRIBUTES;
668 
669 #ifdef CHTYPE_LONG
670         if (attr & A_ALTCHARSET && !(curr & 0xff80))
671         {
672             attr ^= A_ALTCHARSET;
673             curr = acs_map[curr & 0x7f];
674         }
675 #endif
676 
677 #ifndef PDC_WIDE
678         /* Special handling for ACS_BLOCK */
679 
680         if (!(curr & A_CHARTEXT))
681         {
682             curr |= ' ';
683             attr ^= A_REVERSE;
684         }
685 #endif
686         if (attr != old_attr)
687         {
688             if (_new_packet(old_attr, highlight, i, col, row, text) == ERR)
689                 return ERR;
690 
691             old_attr = attr;
692             col += i;
693             i = 0;
694         }
695 
696 #ifdef PDC_WIDE
697         text[i].byte1 = (curr & 0xff00) >> 8;
698         text[i++].byte2 = curr & 0x00ff;
699 #else
700         text[i++] = curr & 0xff;
701 #endif
702     }
703 
704     return _new_packet(old_attr, highlight, i, col, row, text);
705 }
706 
_get_gc(GC * gc,XFontStruct * font_info,int fore,int back)707 static void _get_gc(GC *gc, XFontStruct *font_info, int fore, int back)
708 {
709     XGCValues values;
710 
711     /* Create default Graphics Context */
712 
713     *gc = XCreateGC(XCURSESDISPLAY, XCURSESWIN, 0L, &values);
714 
715     /* specify font */
716 
717     XSetFont(XCURSESDISPLAY, *gc, font_info->fid);
718 
719     XSetForeground(XCURSESDISPLAY, *gc, colors[fore]);
720     XSetBackground(XCURSESDISPLAY, *gc, colors[back]);
721 }
722 
_initialize_colors(void)723 static void _initialize_colors(void)
724 {
725     colors[COLOR_BLACK]   = xc_app_data.colorBlack;
726     colors[COLOR_RED]     = xc_app_data.colorRed;
727     colors[COLOR_GREEN]   = xc_app_data.colorGreen;
728     colors[COLOR_YELLOW]  = xc_app_data.colorYellow;
729     colors[COLOR_BLUE]    = xc_app_data.colorBlue;
730     colors[COLOR_MAGENTA] = xc_app_data.colorMagenta;
731     colors[COLOR_CYAN]    = xc_app_data.colorCyan;
732     colors[COLOR_WHITE]   = xc_app_data.colorWhite;
733 
734     colors[COLOR_BLACK + 8]   = xc_app_data.colorBoldBlack;
735     colors[COLOR_RED + 8]     = xc_app_data.colorBoldRed;
736     colors[COLOR_GREEN + 8]   = xc_app_data.colorBoldGreen;
737     colors[COLOR_YELLOW + 8]  = xc_app_data.colorBoldYellow;
738     colors[COLOR_BLUE + 8]    = xc_app_data.colorBoldBlue;
739     colors[COLOR_MAGENTA + 8] = xc_app_data.colorBoldMagenta;
740     colors[COLOR_CYAN + 8]    = xc_app_data.colorBoldCyan;
741     colors[COLOR_WHITE + 8]   = xc_app_data.colorBoldWhite;
742 
743     colors[COLOR_CURSOR] = xc_app_data.cursorColor;
744     colors[COLOR_BORDER] = xc_app_data.borderColor;
745 }
746 
_refresh_scrollbar(void)747 static void _refresh_scrollbar(void)
748 {
749     XC_LOG(("_refresh_scrollbar() - called\n"));
750 
751     if (SP->sb_on)
752     {
753         PDC_SCROLLBAR_TYPE total_y = SP->sb_total_y;
754         PDC_SCROLLBAR_TYPE total_x = SP->sb_total_x;
755 
756         if (total_y)
757             XawScrollbarSetThumb(scrollVert,
758                 (PDC_SCROLLBAR_TYPE)(SP->sb_cur_y) / total_y,
759                 (PDC_SCROLLBAR_TYPE)(SP->sb_viewport_y) / total_y);
760 
761         if (total_x)
762             XawScrollbarSetThumb(scrollHoriz,
763                 (PDC_SCROLLBAR_TYPE)(SP->sb_cur_x) / total_x,
764                 (PDC_SCROLLBAR_TYPE)(SP->sb_viewport_x) / total_x);
765     }
766 }
767 
_set_cursor_color(chtype * ch,short * fore,short * back)768 static void _set_cursor_color(chtype *ch, short *fore, short *back)
769 {
770     int attr;
771     short f, b;
772 
773     attr = PAIR_NUMBER(*ch);
774 
775     if (attr)
776     {
777         PDC_pair_content(attr, &f, &b);
778         *fore = 7 - (f % 8);
779         *back = 7 - (b % 8);
780     }
781     else
782     {
783         if (*ch & A_REVERSE)
784         {
785             *back = COLOR_BLACK;
786             *fore = COLOR_WHITE;
787         }
788         else
789         {
790             *back = COLOR_WHITE;
791             *fore = COLOR_BLACK;
792         }
793     }
794 }
795 
_get_icon(void)796 static void _get_icon(void)
797 {
798     XIconSize *icon_size;
799     int size_count = 0;
800     Status rc;
801     unsigned char *bitmap_bits = NULL;
802     unsigned icon_bitmap_width = 0, icon_bitmap_height = 0,
803              file_bitmap_width = 0, file_bitmap_height = 0;
804 
805     XC_LOG(("_get_icon() - called\n"));
806 
807     icon_size = XAllocIconSize();
808 
809     rc = XGetIconSizes(XtDisplay(topLevel),
810                        RootWindowOfScreen(XtScreen(topLevel)),
811                        &icon_size, &size_count);
812 
813     /* if the WM can advise on icon sizes... */
814 
815     if (rc && size_count)
816     {
817         int i, max_height = 0, max_width = 0;
818 
819         PDC_LOG(("%s:size_count: %d rc: %d\n", XCLOGMSG, size_count, rc));
820 
821         for (i = 0; i < size_count; i++)
822         {
823             if (icon_size[i].max_width > max_width)
824                 max_width = icon_size[i].max_width;
825             if (icon_size[i].max_height > max_height)
826                 max_height = icon_size[i].max_height;
827 
828             PDC_LOG(("%s:min: %d %d\n", XCLOGMSG,
829                      icon_size[i].min_width, icon_size[i].min_height));
830 
831             PDC_LOG(("%s:max: %d %d\n", XCLOGMSG,
832                      icon_size[i].max_width, icon_size[i].max_height));
833 
834             PDC_LOG(("%s:inc: %d %d\n", XCLOGMSG,
835                      icon_size[i].width_inc, icon_size[i].height_inc));
836         }
837 
838         if (max_width >= big_icon_width && max_height >= big_icon_height)
839         {
840             icon_bitmap_width = big_icon_width;
841             icon_bitmap_height = big_icon_height;
842             bitmap_bits = (unsigned char *)big_icon_bits;
843         }
844         else
845         {
846             icon_bitmap_width = little_icon_width;
847             icon_bitmap_height = little_icon_height;
848             bitmap_bits = (unsigned char *)little_icon_bits;
849         }
850 
851     }
852     else  /* use small icon */
853     {
854         icon_bitmap_width = little_icon_width;
855         icon_bitmap_height = little_icon_height;
856         bitmap_bits = (unsigned char *)little_icon_bits;
857     }
858 
859     XFree(icon_size);
860 
861 #ifdef HAVE_XPM_H
862     if (xc_app_data.pixmap && xc_app_data.pixmap[0]) /* supplied pixmap */
863     {
864         XpmReadFileToPixmap(XtDisplay(topLevel),
865                             RootWindowOfScreen(XtScreen(topLevel)),
866                             (char *)xc_app_data.pixmap,
867                             &icon_pixmap, &icon_pixmap_mask, NULL);
868         return;
869     }
870 #endif
871 
872     if (xc_app_data.bitmap && xc_app_data.bitmap[0]) /* supplied bitmap */
873     {
874         int x_hot = 0, y_hot = 0;
875 
876         rc = XReadBitmapFile(XtDisplay(topLevel),
877                              RootWindowOfScreen(XtScreen(topLevel)),
878                              (char *)xc_app_data.bitmap,
879                              &file_bitmap_width, &file_bitmap_height,
880                              &icon_bitmap, &x_hot, &y_hot);
881 
882         switch(rc)
883         {
884         case BitmapOpenFailed:
885             fprintf(stderr, "bitmap file %s: not found\n",
886                     xc_app_data.bitmap);
887             break;
888         case BitmapFileInvalid:
889             fprintf(stderr, "bitmap file %s: contents invalid\n",
890                     xc_app_data.bitmap);
891             break;
892         default:
893             return;
894         }
895     }
896 
897     icon_bitmap = XCreateBitmapFromData(XtDisplay(topLevel),
898         RootWindowOfScreen(XtScreen(topLevel)),
899         (char *)bitmap_bits, icon_bitmap_width, icon_bitmap_height);
900 }
901 
_draw_border(void)902 static void _draw_border(void)
903 {
904     /* Draw the border if required */
905 
906     if (xc_app_data.borderWidth)
907         XDrawRectangle(XCURSESDISPLAY, XCURSESWIN, border_gc,
908                        xc_app_data.borderWidth / 2,
909                        xc_app_data.borderWidth / 2,
910                        window_width - xc_app_data.borderWidth,
911                        window_height - xc_app_data.borderWidth);
912 }
913 
914 /* Redraw the entire screen */
915 
_display_screen(void)916 static void _display_screen(void)
917 {
918     int row;
919 
920     XC_LOG(("_display_screen() - called\n"));
921 
922     for (row = 0; row < XCursesLINES; row++)
923     {
924         XC_get_line_lock(row);
925 
926         _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row)),
927                       row, 0, COLS, FALSE);
928 
929         XC_release_line_lock(row);
930     }
931 
932     _redraw_cursor();
933     _draw_border();
934 }
935 
936 /* Draw changed portions of the screen */
937 
_refresh_screen(void)938 static void _refresh_screen(void)
939 {
940     int row, start_col, num_cols;
941 
942     XC_LOG(("_refresh_screen() - called\n"));
943 
944     for (row = 0; row < XCursesLINES; row++)
945     {
946         num_cols = (int)*(Xcurscr + XCURSCR_LENGTH_OFF + row);
947 
948         if (num_cols)
949         {
950             XC_get_line_lock(row);
951 
952             start_col = (int)*(Xcurscr + XCURSCR_START_OFF + row);
953 
954             _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row) +
955                           (start_col * sizeof(chtype))), row, start_col,
956                           num_cols, FALSE);
957 
958             *(Xcurscr + XCURSCR_LENGTH_OFF + row) = 0;
959 
960             XC_release_line_lock(row);
961         }
962     }
963 
964     if (mouse_selection)
965         _selection_off();
966 }
967 
_handle_expose(Widget w,XtPointer client_data,XEvent * event,Boolean * unused)968 static void _handle_expose(Widget w, XtPointer client_data, XEvent *event,
969                            Boolean *unused)
970 {
971     XC_LOG(("_handle_expose() - called\n"));
972 
973     /* ignore all Exposes except last */
974 
975     if (event->xexpose.count)
976         return;
977 
978     if (after_first_curses_request && received_map_notify)
979         _display_screen();
980 }
981 
_handle_nonmaskable(Widget w,XtPointer client_data,XEvent * event,Boolean * unused)982 static void _handle_nonmaskable(Widget w, XtPointer client_data, XEvent *event,
983                                 Boolean *unused)
984 {
985     XClientMessageEvent *client_event = (XClientMessageEvent *)event;
986 
987     PDC_LOG(("%s:_handle_nonmaskable called: xc_otherpid %d event %d\n",
988              XCLOGMSG, xc_otherpid, event->type));
989 
990     if (event->type == ClientMessage)
991     {
992         XC_LOG(("ClientMessage received\n"));
993 
994         /* This code used to include handling of WM_SAVE_YOURSELF, but
995            it resulted in continual failure of THE on my Toshiba laptop.
996            Removed on 3-3-2001. Now only exits on WM_DELETE_WINDOW. */
997 
998         if ((Atom)client_event->data.s[0] == wm_atom[0])
999             _exit_process(0, SIGKILL, "");
1000     }
1001 }
1002 
XCursesKeyPress(Widget w,XEvent * event,String * params,Cardinal * nparams)1003 static void XCursesKeyPress(Widget w, XEvent *event, String *params,
1004                             Cardinal *nparams)
1005 {
1006     enum { STATE_NORMAL, STATE_COMPOSE, STATE_CHAR };
1007 
1008 #ifdef PDC_XIM
1009     Status status;
1010     wchar_t buffer[120];
1011 #else
1012     unsigned char buffer[120];
1013     XComposeStatus compose;
1014     static int compose_state = STATE_NORMAL;
1015     static int compose_index = 0;
1016     int char_idx = 0;
1017 #endif
1018     unsigned long key = 0;
1019     int buflen = 40;
1020     int i, count;
1021     unsigned long modifier = 0;
1022     bool key_code = FALSE;
1023 
1024     XC_LOG(("XCursesKeyPress() - called\n"));
1025 
1026     /* Handle modifier keys first; ignore other KeyReleases */
1027 
1028     if (event->type == KeyRelease)
1029     {
1030         /* The keysym value was set by a previous call to this function
1031            with a KeyPress event (or reset by the mouse event handler) */
1032 
1033         if (SP->return_key_modifiers &&
1034 #ifndef PDC_XIM
1035             keysym != compose_key &&
1036 #endif
1037             IsModifierKey(keysym))
1038         {
1039             switch (keysym) {
1040             case XK_Shift_L:
1041                 key = KEY_SHIFT_L;
1042                 break;
1043             case XK_Shift_R:
1044                 key = KEY_SHIFT_R;
1045                 break;
1046             case XK_Control_L:
1047                 key = KEY_CONTROL_L;
1048                 break;
1049             case XK_Control_R:
1050                 key = KEY_CONTROL_R;
1051                 break;
1052             case XK_Alt_L:
1053                 key = KEY_ALT_L;
1054                 break;
1055             case XK_Alt_R:
1056                 key = KEY_ALT_R;
1057             }
1058 
1059             if (key)
1060                 _send_key_to_curses(key, NULL, TRUE);
1061         }
1062 
1063         return;
1064     }
1065 
1066     buffer[0] = '\0';
1067 
1068 #ifdef PDC_XIM
1069     count = XwcLookupString(Xic, &(event->xkey), buffer, buflen,
1070                             &keysym, &status);
1071 #else
1072     count = XLookupString(&(event->xkey), (char *)buffer, buflen,
1073                           &keysym, &compose);
1074 #endif
1075 
1076     /* translate keysym into curses key code */
1077 
1078     PDC_LOG(("%s:Key mask: %x\n", XCLOGMSG, event->xkey.state));
1079 
1080 #ifdef PDCDEBUG
1081     for (i = 0; i < 4; i++)
1082         PDC_debug("%s:Keysym %x %d\n", XCLOGMSG,
1083                   XKeycodeToKeysym(XCURSESDISPLAY, event->xkey.keycode, i), i);
1084 #endif
1085 
1086 #ifndef PDC_XIM
1087 
1088     /* Check if the key just pressed is the user-specified compose
1089        key; if it is, set the compose state and exit. */
1090 
1091     if (keysym == compose_key)
1092     {
1093         chtype *ch;
1094         int xpos, ypos, save_visibility = SP->visibility;
1095         short fore = 0, back = 0;
1096 
1097         /* Change the shape of the cursor to an outline rectangle to
1098            indicate we are in "compose" status */
1099 
1100         SP->visibility = 0;
1101 
1102         _redraw_cursor();
1103 
1104         SP->visibility = save_visibility;
1105         _make_xy(SP->curscol, SP->cursrow, &xpos, &ypos);
1106 
1107         ch = (chtype *)(Xcurscr + XCURSCR_Y_OFF(SP->cursrow) +
1108              (SP->curscol * sizeof(chtype)));
1109 
1110         _set_cursor_color(ch, &fore, &back);
1111 
1112         XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]);
1113 
1114         XDrawRectangle(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc,
1115                        xpos + 1, ypos - font_height +
1116                        xc_app_data.normalFont->descent + 1,
1117                        font_width - 2, font_height - 2);
1118 
1119         compose_state = STATE_COMPOSE;
1120         return;
1121     }
1122 
1123     switch (compose_state)
1124     {
1125     case STATE_COMPOSE:
1126         if (IsModifierKey(keysym))
1127             return;
1128 
1129         if (event->xkey.state & compose_mask)
1130         {
1131             compose_state = STATE_NORMAL;
1132             _redraw_cursor();
1133             break;
1134         }
1135 
1136         if (buffer[0] && count == 1)
1137             key = buffer[0];
1138 
1139         compose_index = -1;
1140 
1141         for (i = 0; i < (int)strlen(compose_chars); i++)
1142             if (compose_chars[i] == key)
1143             {
1144                 compose_index = i;
1145                 break;
1146             }
1147 
1148         if (compose_index == -1)
1149         {
1150             compose_state = STATE_NORMAL;
1151             compose_index = 0;
1152             _redraw_cursor();
1153             break;
1154         }
1155 
1156         compose_state = STATE_CHAR;
1157         return;
1158 
1159     case STATE_CHAR:
1160         if (IsModifierKey(keysym))
1161             return;
1162 
1163         if (event->xkey.state & compose_mask)
1164         {
1165             compose_state = STATE_NORMAL;
1166             _redraw_cursor();
1167             break;
1168         }
1169 
1170         if (buffer[0] && count == 1)
1171             key = buffer[0];
1172 
1173         char_idx = -1;
1174 
1175         for (i = 0; i < MAX_COMPOSE_CHARS; i++)
1176             if (compose_lookups[compose_index][i] == key)
1177             {
1178                 char_idx = i;
1179                 break;
1180             }
1181 
1182         if (char_idx == -1)
1183         {
1184             compose_state = STATE_NORMAL;
1185             compose_index = 0;
1186             _redraw_cursor();
1187             break;
1188         }
1189 
1190         _send_key_to_curses(compose_keys[compose_index][char_idx],
1191             NULL, FALSE);
1192 
1193         compose_state = STATE_NORMAL;
1194         compose_index = 0;
1195 
1196         _redraw_cursor();
1197 
1198         return;
1199     }
1200 
1201 #endif /* PDC_XIM */
1202 
1203     /* To get here we are procesing "normal" keys */
1204 
1205     PDC_LOG(("%s:Keysym %x %d\n", XCLOGMSG,
1206              XKeycodeToKeysym(XCURSESDISPLAY, event->xkey.keycode, key), key));
1207 
1208     if (SP->save_key_modifiers)
1209     {
1210         /* 0x10: usually, numlock modifier */
1211 
1212         if (event->xkey.state & Mod2Mask)
1213             modifier |= PDC_KEY_MODIFIER_NUMLOCK;
1214 
1215         /* 0x01: shift modifier */
1216 
1217         if (event->xkey.state & ShiftMask)
1218             modifier |= PDC_KEY_MODIFIER_SHIFT;
1219 
1220         /* 0x04: control modifier */
1221 
1222         if (event->xkey.state & ControlMask)
1223             modifier |= PDC_KEY_MODIFIER_CONTROL;
1224 
1225         /* 0x08: usually, alt modifier */
1226 
1227         if (event->xkey.state & Mod1Mask)
1228             modifier |= PDC_KEY_MODIFIER_ALT;
1229     }
1230 
1231     for (i = 0; key_table[i].keycode; i++)
1232     {
1233         if (key_table[i].keycode == keysym)
1234         {
1235             PDC_LOG(("%s:State %x\n", XCLOGMSG, event->xkey.state));
1236 
1237             /* ControlMask: 0x04: control modifier
1238                Mod1Mask: 0x08: usually, alt modifier
1239                Mod2Mask: 0x10: usually, numlock modifier
1240                ShiftMask: 0x01: shift modifier */
1241 
1242             if ((event->xkey.state & ShiftMask) ||
1243                 (key_table[i].numkeypad &&
1244                 (event->xkey.state & Mod2Mask)))
1245             {
1246                 key = key_table[i].shifted;
1247             }
1248             else if (event->xkey.state & ControlMask)
1249             {
1250                 key = key_table[i].control;
1251             }
1252             else if (event->xkey.state & Mod1Mask)
1253             {
1254                 key = key_table[i].alt;
1255             }
1256 
1257             /* To get here, we ignore all other modifiers */
1258 
1259             else
1260                 key = key_table[i].normal;
1261 
1262             key_code = (key > 0x100);
1263             break;
1264         }
1265     }
1266 
1267     if (!key && buffer[0] && count == 1)
1268         key = buffer[0];
1269 
1270     PDC_LOG(("%s:Key: %s pressed - %x Mod: %x\n", XCLOGMSG,
1271              XKeysymToString(keysym), key, event->xkey.state));
1272 
1273     /* Handle ALT letters and numbers */
1274 
1275     if (event->xkey.state == Mod1Mask)
1276     {
1277         if (key >= 'A' && key <= 'Z')
1278         {
1279             key += ALT_A - 'A';
1280             key_code = TRUE;
1281         }
1282 
1283         if (key >= 'a' && key <= 'z')
1284         {
1285             key += ALT_A - 'a';
1286             key_code = TRUE;
1287         }
1288 
1289         if (key >= '0' && key <= '9')
1290         {
1291             key += ALT_0 - '0';
1292             key_code = TRUE;
1293         }
1294     }
1295 
1296     /* After all that, send the key back to the application if is
1297        NOT zero. */
1298 
1299     if (key)
1300     {
1301         key |= (modifier << 24);
1302 
1303         _send_key_to_curses(key, NULL, key_code);
1304     }
1305 }
1306 
XCursesHandleString(Widget w,XEvent * event,String * params,Cardinal * nparams)1307 static void XCursesHandleString(Widget w, XEvent *event, String *params,
1308                                 Cardinal *nparams)
1309 {
1310     unsigned char *ptr;
1311 
1312     if (*nparams != 1)
1313         return;
1314 
1315     ptr = (unsigned char *)*params;
1316 
1317     if (ptr[0] == '0' && ptr[1] == 'x' && ptr[2] != '\0')
1318     {
1319         unsigned char c;
1320         unsigned long total = 0;
1321 
1322         for (ptr += 2; (c = tolower(*ptr)); ptr++)
1323         {
1324             total <<= 4;
1325 
1326             if (c >= '0' && c <= '9')
1327                 total += c - '0';
1328             else
1329                 if (c >= 'a' && c <= 'f')
1330                     total += c - ('a' - 10);
1331                 else
1332                     break;
1333         }
1334 
1335         if (c == '\0')
1336             _send_key_to_curses(total, NULL, FALSE);
1337     }
1338     else
1339         for (; *ptr; ptr++)
1340             _send_key_to_curses((unsigned long)*ptr, NULL, FALSE);
1341 }
1342 
_paste_string(Widget w,XtPointer data,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)1343 static void _paste_string(Widget w, XtPointer data, Atom *selection, Atom *type,
1344                           XtPointer value, unsigned long *length, int *format)
1345 {
1346     unsigned long i, key;
1347     unsigned char *string = value;
1348 
1349     XC_LOG(("_paste_string() - called\n"));
1350 
1351     if (!*type || !*length || !string)
1352         return;
1353 
1354     for (i = 0; string[i] && (i < (*length)); i++)
1355     {
1356         key = string[i];
1357 
1358         if (key == 10)      /* new line - convert to ^M */
1359             key = 13;
1360 
1361         _send_key_to_curses(key, NULL, FALSE);
1362     }
1363 
1364     XtFree(value);
1365 }
1366 
_paste_utf8(Widget w,XtPointer event,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)1367 static void _paste_utf8(Widget w, XtPointer event, Atom *selection, Atom *type,
1368                         XtPointer value, unsigned long *length, int *format)
1369 {
1370     wchar_t key;
1371     size_t i = 0, len;
1372     char *string = value;
1373 
1374     XC_LOG(("_paste_utf8() - called\n"));
1375 
1376     if (!*type || !*length)
1377     {
1378         XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _paste_string,
1379                             event, ((XButtonEvent *)event)->time);
1380         return;
1381     }
1382 
1383     len = *length;
1384 
1385     if (!string)
1386         return;
1387 
1388     while (string[i] && (i < len))
1389     {
1390         int retval = _from_utf8(&key, string + i, len - i);
1391 
1392         if (retval < 1)
1393             return;
1394 
1395         if (key == 10)      /* new line - convert to ^M */
1396             key = 13;
1397 
1398         _send_key_to_curses(key, NULL, FALSE);
1399 
1400         i += retval;
1401     }
1402 
1403     XtFree(value);
1404 }
1405 
XCursesPasteSelection(Widget w,XButtonEvent * button_event)1406 static void XCursesPasteSelection(Widget w, XButtonEvent *button_event)
1407 {
1408     XC_LOG(("XCursesPasteSelection() - called\n"));
1409 
1410     XtGetSelectionValue(w, XA_PRIMARY, XA_UTF8_STRING(XtDisplay(w)),
1411                         _paste_utf8, (XtPointer)button_event,
1412                         button_event->time);
1413 }
1414 
_convert_proc(Widget w,Atom * selection,Atom * target,Atom * type_return,XtPointer * value_return,unsigned long * length_return,int * format_return)1415 static Boolean _convert_proc(Widget w, Atom *selection, Atom *target,
1416                              Atom *type_return, XtPointer *value_return,
1417                              unsigned long *length_return, int *format_return)
1418 {
1419     XC_LOG(("_convert_proc() - called\n"));
1420 
1421     if (*target == XA_TARGETS(XtDisplay(topLevel)))
1422     {
1423         XSelectionRequestEvent *req = XtGetSelectionRequest(w,
1424             *selection, (XtRequestId)NULL);
1425 
1426         Atom *targetP;
1427         XPointer std_targets;
1428         unsigned long std_length;
1429 
1430         XmuConvertStandardSelection(topLevel, req->time, selection,
1431                                     target, type_return, &std_targets,
1432                                     &std_length, format_return);
1433 
1434         *length_return = std_length + 2;
1435         *value_return = XtMalloc(sizeof(Atom) * (*length_return));
1436 
1437         targetP = *(Atom**)value_return;
1438         *targetP++ = XA_STRING;
1439         *targetP++ = XA_UTF8_STRING(XtDisplay(topLevel));
1440 
1441         memmove((void *)targetP, (const void *)std_targets,
1442                 sizeof(Atom) * std_length);
1443 
1444         XtFree((char *)std_targets);
1445         *type_return = XA_ATOM;
1446         *format_return = sizeof(Atom) * 8;
1447 
1448         return True;
1449     }
1450     else if (*target == XA_UTF8_STRING(XtDisplay(topLevel)) ||
1451              *target == XA_STRING)
1452     {
1453         bool utf8 = !(*target == XA_STRING);
1454         char *data = XtMalloc(tmpsel_length * 3 + 1);
1455         chtype *tmp = tmpsel;
1456         int ret_length = 0;
1457 
1458         if (utf8)
1459         {
1460             while (*tmp)
1461                 ret_length += _to_utf8(data + ret_length, *tmp++);
1462         }
1463         else
1464             while (*tmp)
1465                 data[ret_length++] = *tmp++ & 0xff;
1466 
1467         data[ret_length++] = '\0';
1468 
1469         *value_return = data;
1470         *length_return = ret_length;
1471         *format_return = 8;
1472         *type_return = *target;
1473 
1474         return True;
1475     }
1476     else
1477         return XmuConvertStandardSelection(topLevel, CurrentTime,
1478             selection, target, type_return, (XPointer*)value_return,
1479             length_return, format_return);
1480 }
1481 
_lose_ownership(Widget w,Atom * type)1482 static void _lose_ownership(Widget w, Atom *type)
1483 {
1484     XC_LOG(("_lose_ownership() - called\n"));
1485 
1486     if (tmpsel)
1487         free(tmpsel);
1488 
1489     tmpsel = NULL;
1490     tmpsel_length = 0;
1491     _selection_off();
1492 }
1493 
_show_selection(int start_x,int start_y,int end_x,int end_y,bool highlight)1494 static void _show_selection(int start_x, int start_y, int end_x, int end_y,
1495                             bool highlight)
1496 {
1497     int i, num_cols, start_col, row;
1498 
1499     PDC_LOG(("%s:_show_selection() - called StartX: %d StartY: %d "
1500              "EndX: %d EndY: %d Highlight: %d\n", XCLOGMSG,
1501              start_x, start_y, end_x, end_y, highlight));
1502 
1503     for (i = 0; i < end_y - start_y + 1; i++)
1504     {
1505         if (start_y == end_y)       /* only one line */
1506         {
1507             start_col = start_x;
1508             num_cols = end_x - start_x + 1;
1509             row = start_y;
1510         }
1511         else if (!i)            /* first line */
1512         {
1513             start_col = start_x;
1514             num_cols = COLS - start_x;
1515             row = start_y;
1516         }
1517         else if (start_y + i == end_y)  /* last line */
1518         {
1519             start_col = 0;
1520             num_cols = end_x + 1;
1521             row = end_y;
1522         }
1523         else                /* full line */
1524         {
1525             start_col = 0;
1526             num_cols = COLS;
1527             row = start_y + i;
1528         }
1529 
1530         XC_get_line_lock(row);
1531 
1532         _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row) +
1533                       (start_col * sizeof(chtype))), row, start_col,
1534                       num_cols, highlight);
1535 
1536         XC_release_line_lock(row);
1537     }
1538 }
1539 
_selection_off(void)1540 static void _selection_off(void)
1541 {
1542     XC_LOG(("_selection_off() - called\n"));
1543 
1544     _display_screen();
1545 
1546     selection_start_x = selection_start_y = selection_end_x =
1547         selection_end_y = 0;
1548 
1549     mouse_selection = FALSE;
1550 }
1551 
_selection_on(int x,int y)1552 static void _selection_on(int x, int y)
1553 {
1554     XC_LOG(("_selection_on() - called\n"));
1555 
1556     selection_start_x = selection_end_x = x;
1557     selection_start_y = selection_end_y = y;
1558 }
1559 
_selection_extend(int x,int y)1560 static void _selection_extend(int x, int y)
1561 {
1562     int temp, current_start, current_end, current_start_x,
1563         current_end_x, current_start_y, current_end_y, new_start,
1564         new_end, new_start_x, new_end_x, new_start_y, new_end_y;
1565 
1566     XC_LOG(("_selection_extend() - called\n"));
1567 
1568     mouse_selection = TRUE;
1569 
1570     /* convert x/y coordinates into start/stop */
1571 
1572     current_start = (selection_start_y * COLS) + selection_start_x;
1573     current_end = (selection_end_y * COLS) + selection_end_x;
1574 
1575     if (current_start > current_end)
1576     {
1577         current_start_x = selection_end_x;
1578         current_start_y = selection_end_y;
1579         current_end_x = selection_start_x;
1580         current_end_y = selection_start_y;
1581         temp = current_start;
1582         current_start = current_end;
1583         current_end = temp;
1584     }
1585     else
1586     {
1587         current_end_x = selection_end_x;
1588         current_end_y = selection_end_y;
1589         current_start_x = selection_start_x;
1590         current_start_y = selection_start_y;
1591     }
1592 
1593     /* Now we have the current selection as a linear expression.
1594        Convert the new position to a linear expression. */
1595 
1596     selection_end_x = x;
1597     selection_end_y = y;
1598 
1599     /* convert x/y coordinates into start/stop */
1600 
1601     new_start = (selection_start_y * COLS) + selection_start_x;
1602     new_end = (selection_end_y * COLS) + selection_end_x;
1603 
1604     if (new_start > new_end)
1605     {
1606         new_start_x = selection_end_x;
1607         new_start_y = selection_end_y;
1608         new_end_x = selection_start_x;
1609         new_end_y = selection_start_y;
1610         temp = new_start;
1611         new_start = new_end;
1612         new_end = temp;
1613     }
1614     else
1615     {
1616         new_end_x = selection_end_x;
1617         new_end_y = selection_end_y;
1618         new_start_x = selection_start_x;
1619         new_start_y = selection_start_y;
1620     }
1621 
1622     if (new_end > current_end)
1623         _show_selection(current_end_x, current_end_y, new_end_x,
1624                         new_end_y, TRUE);
1625     else if (new_end < current_end)
1626         _show_selection(new_end_x, new_end_y, current_end_x,
1627                         current_end_y, FALSE);
1628     else if (new_start < current_start)
1629         _show_selection(new_start_x, new_start_y, current_start_x,
1630                         current_start_y, TRUE);
1631     else if (new_start > current_start)
1632         _show_selection(current_start_x, current_start_y,
1633                         new_start_x, new_start_y, FALSE);
1634     else
1635         _show_selection(current_start_x, current_start_y,
1636                         new_start_x, new_start_y, TRUE);
1637 }
1638 
_selection_set(void)1639 static void _selection_set(void)
1640 {
1641     int i, j, start, end, start_x, end_x, start_y, end_y, num_cols,
1642         start_col, row, num_chars, ch, last_nonblank, length, newlen;
1643     chtype *ptr = NULL;
1644 
1645     XC_LOG(("_selection_set() - called\n"));
1646 
1647     /* convert x/y coordinates into start/stop */
1648 
1649     start = (selection_start_y * COLS) + selection_start_x;
1650     end = (selection_end_y * COLS) + selection_end_x;
1651 
1652     if (start == end)
1653     {
1654         if (tmpsel)
1655             free(tmpsel);
1656 
1657         tmpsel = NULL;
1658         tmpsel_length = 0;
1659 
1660         return;
1661     }
1662 
1663     if (start > end)
1664     {
1665         start_x = selection_end_x;
1666         start_y = selection_end_y;
1667         end_x = selection_start_x;
1668         end_y = selection_start_y;
1669         length = start - end + 1;
1670     }
1671     else
1672     {
1673         end_x = selection_end_x;
1674         end_y = selection_end_y;
1675         start_x = selection_start_x;
1676         start_y = selection_start_y;
1677         length = end - start + 1;
1678     }
1679 
1680     newlen = length + end_y - start_y + 2;
1681 
1682     if (length > (int)tmpsel_length)
1683     {
1684         if (!tmpsel_length)
1685             tmpsel = malloc(newlen * sizeof(chtype));
1686         else
1687             tmpsel = realloc(tmpsel, newlen * sizeof(chtype));
1688     }
1689 
1690     if (!tmpsel)
1691     {
1692         tmpsel_length = 0;
1693         return;
1694     }
1695 
1696     tmpsel_length = length;
1697     num_chars = 0;
1698 
1699     for (i = 0; i < end_y - start_y + 1; i++)
1700     {
1701 
1702         if (start_y == end_y)       /* only one line */
1703         {
1704             start_col = start_x;
1705             num_cols = end_x - start_x + 1;
1706             row = start_y;
1707         }
1708         else if (!i)            /* first line */
1709         {
1710             start_col = start_x;
1711             num_cols = COLS - start_x;
1712             row = start_y;
1713         }
1714         else if (start_y + i == end_y)  /* last line */
1715         {
1716             start_col = 0;
1717             num_cols = end_x + 1;
1718             row = end_y;
1719         }
1720         else                /* full line */
1721         {
1722             start_col = 0;
1723             num_cols = COLS;
1724             row = start_y + i;
1725         }
1726 
1727         XC_get_line_lock(row);
1728 
1729         ptr = (chtype *)(Xcurscr + XCURSCR_Y_OFF(row) +
1730               start_col * sizeof(chtype));
1731 
1732         if (i < end_y - start_y)
1733         {
1734             last_nonblank = 0;
1735 
1736             for (j = 0; j < num_cols; j++)
1737             {
1738                 ch = (int)(ptr[j] & A_CHARTEXT);
1739                 if (ch != (int)' ')
1740                     last_nonblank = j;
1741             }
1742         }
1743         else
1744             last_nonblank = num_cols - 1;
1745 
1746         for (j = 0; j <= last_nonblank; j++)
1747             tmpsel[num_chars++] = ptr[j];
1748 
1749         XC_release_line_lock(row);
1750 
1751         if (i < end_y - start_y)
1752             tmpsel[num_chars++] = '\n';
1753     }
1754 
1755     tmpsel[num_chars] = '\0';
1756     tmpsel_length = num_chars;
1757 }
1758 
_display_cursor(int old_row,int old_x,int new_row,int new_x)1759 static void _display_cursor(int old_row, int old_x, int new_row, int new_x)
1760 {
1761     int xpos, ypos, i;
1762     chtype *ch;
1763     short fore = 0, back = 0;
1764 
1765     PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n",
1766              XCLOGMSG, old_row, old_x));
1767 
1768     /* if the cursor position is outside the boundary of the screen,
1769        ignore the request */
1770 
1771     if (old_row >= XCursesLINES || old_x >= COLS ||
1772         new_row >= XCursesLINES || new_x >= COLS)
1773         return;
1774 
1775     /* display the character at the current cursor position */
1776 
1777     PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n",
1778              XCLOGMSG, old_row, old_x));
1779 
1780     _display_text((const chtype *)(Xcurscr + (XCURSCR_Y_OFF(old_row) +
1781                   (old_x * sizeof(chtype)))), old_row, old_x, 1, FALSE);
1782 
1783     /* display the cursor at the new cursor position */
1784 
1785     if (!SP->visibility)
1786         return;     /* cursor not displayed, no more to do */
1787 
1788     _make_xy(new_x, new_row, &xpos, &ypos);
1789 
1790     ch = (chtype *)(Xcurscr + XCURSCR_Y_OFF(new_row) + new_x * sizeof(chtype));
1791 
1792     _set_cursor_color(ch, &fore, &back);
1793 
1794     if (vertical_cursor)
1795     {
1796         XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]);
1797 
1798         for (i = 1; i <= SP->visibility; i++)
1799             XDrawLine(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc,
1800                       xpos + i, ypos - xc_app_data.normalFont->ascent,
1801                       xpos + i, ypos - xc_app_data.normalFont->ascent +
1802                       font_height - 1);
1803     }
1804     else
1805     {
1806         if (SP->visibility == 1)
1807         {
1808             /* cursor visibility normal */
1809 
1810             XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]);
1811 
1812             for (i = 0; i < xc_app_data.normalFont->descent + 2; i++)
1813                 XDrawLine(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc,
1814                           xpos, ypos - 2 + i, xpos + font_width, ypos - 2 + i);
1815         }
1816         else
1817         {
1818             /* cursor visibility high */
1819 #ifdef PDC_WIDE
1820             XChar2b buf[2];
1821 
1822             buf[0].byte1 = (*ch & 0xff00) >> 8;
1823             buf[0].byte2 = *ch & 0x00ff;
1824 
1825             buf[1].byte1 = buf[1].byte2 = 0;
1826 #else
1827             char buf[2];
1828 
1829             buf[0] = *ch & 0xff;
1830             buf[1] = '\0';
1831 #endif
1832             XSetForeground(XCURSESDISPLAY, block_cursor_gc, colors[fore]);
1833             XSetBackground(XCURSESDISPLAY, block_cursor_gc, colors[back]);
1834 #ifdef PDC_WIDE
1835             XDrawImageString16(
1836 #else
1837             XDrawImageString(
1838 #endif
1839                              XCURSESDISPLAY, XCURSESWIN, block_cursor_gc,
1840                              xpos, ypos, buf, 1);
1841         }
1842     }
1843 
1844     PDC_LOG(("%s:_display_cursor() - draw cursor at row %d col %d\n",
1845              XCLOGMSG, new_row, new_x));
1846 }
1847 
_redraw_cursor(void)1848 static void _redraw_cursor(void)
1849 {
1850     _display_cursor(SP->cursrow, SP->curscol, SP->cursrow, SP->curscol);
1851 }
1852 
_handle_enter_leave(Widget w,XtPointer client_data,XEvent * event,Boolean * unused)1853 static void _handle_enter_leave(Widget w, XtPointer client_data,
1854                                 XEvent *event, Boolean *unused)
1855 {
1856     XC_LOG(("_handle_enter_leave called\n"));
1857 
1858     switch(event->type)
1859     {
1860     case EnterNotify:
1861         XC_LOG(("EnterNotify received\n"));
1862 
1863         window_entered = TRUE;
1864         break;
1865 
1866     case LeaveNotify:
1867         XC_LOG(("LeaveNotify received\n"));
1868 
1869         window_entered = FALSE;
1870 
1871         /* Display the cursor so it stays on while the window is
1872            not current */
1873 
1874         _redraw_cursor();
1875         break;
1876 
1877     default:
1878         PDC_LOG(("%s:_handle_enter_leave - unknown event %d\n",
1879                  XCLOGMSG, event->type));
1880     }
1881 }
1882 
_send_key_to_curses(unsigned long key,MOUSE_STATUS * ms,bool key_code)1883 static void _send_key_to_curses(unsigned long key, MOUSE_STATUS *ms,
1884                                 bool key_code)
1885 {
1886     PDC_LOG(("%s:_send_key_to_curses() - called: sending %d\n",
1887              XCLOGMSG, key));
1888 
1889     SP->key_code = key_code;
1890 
1891     if (XC_write_socket(xc_key_sock, &key, sizeof(unsigned long)) < 0)
1892         _exit_process(1, SIGKILL, "exiting from _send_key_to_curses");
1893 
1894     if (ms)
1895     {
1896         MOUSE_LOG(("%s:writing mouse stuff\n", XCLOGMSG));
1897 
1898         if (XC_write_socket(xc_key_sock, ms, sizeof(MOUSE_STATUS)) < 0)
1899             _exit_process(1, SIGKILL, "exiting from _send_key_to_curses");
1900     }
1901 }
1902 
_blink_cursor(XtPointer unused,XtIntervalId * id)1903 static void _blink_cursor(XtPointer unused, XtIntervalId *id)
1904 {
1905     XC_LOG(("_blink_cursor() - called:\n"));
1906 
1907     if (window_entered)
1908     {
1909         if (visible_cursor)
1910         {
1911             /* Cursor currently ON, turn it off */
1912 
1913             int save_visibility = SP->visibility;
1914             SP->visibility = 0;
1915             _redraw_cursor();
1916             SP->visibility = save_visibility;
1917             visible_cursor = FALSE;
1918         }
1919         else
1920         {
1921             /* Cursor currently OFF, turn it on */
1922 
1923             _redraw_cursor();
1924             visible_cursor = TRUE;
1925         }
1926     }
1927 
1928     XtAppAddTimeOut(app_context, xc_app_data.cursorBlinkRate,
1929                     _blink_cursor, NULL);
1930 }
1931 
XCursesButton(Widget w,XEvent * event,String * params,Cardinal * nparams)1932 static void XCursesButton(Widget w, XEvent *event, String *params,
1933                           Cardinal *nparams)
1934 {
1935     int button_no;
1936     static int last_button_no = 0;
1937     static Time last_button_press_time = 0;
1938     MOUSE_STATUS save_mouse_status;
1939     bool send_key = TRUE;
1940     static bool remove_release;
1941     static bool handle_real_release;
1942 
1943     XC_LOG(("XCursesButton() - called\n"));
1944 
1945     keysym = 0; /* suppress any modifier key return */
1946 
1947     save_mouse_status = Mouse_status;
1948     button_no = event->xbutton.button;
1949 
1950     /* It appears that under X11R6 (at least on Linux), that an
1951        event_type of ButtonMotion does not include the mouse button in
1952        the event. The following code is designed to cater for this
1953        situation. */
1954 
1955     if (!button_no)
1956         button_no = last_button_no;
1957 
1958     last_button_no = button_no;
1959 
1960     Mouse_status.changes = 0;
1961 
1962     switch(event->type)
1963     {
1964     case ButtonPress:
1965         /* Handle button 4 and 5, which are normally mapped to the wheel
1966            mouse scroll up and down */
1967 
1968         if (button_no == 4 || button_no == 5)
1969         {
1970             /* Send the KEY_MOUSE to curses program */
1971 
1972             memset(&Mouse_status, 0, sizeof(Mouse_status));
1973 
1974             Mouse_status.changes = (button_no == 5) ?
1975                 PDC_MOUSE_WHEEL_DOWN : PDC_MOUSE_WHEEL_UP;
1976 
1977             MOUSE_X_POS = MOUSE_Y_POS = -1;
1978             _send_key_to_curses(KEY_MOUSE, &Mouse_status, TRUE);
1979             remove_release = TRUE;
1980 
1981             return;
1982         }
1983 
1984         if (button_no == 2 &&
1985             (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
1986         {
1987             XCursesPasteSelection(drawing, (XButtonEvent *)event);
1988             remove_release = TRUE;
1989 
1990             return;
1991         }
1992 
1993         remove_release = False;
1994         handle_real_release = False;
1995 
1996         MOUSE_LOG(("\nButtonPress\n"));
1997 
1998         if ((event->xbutton.time - last_button_press_time) <
1999             xc_app_data.doubleClickPeriod)
2000         {
2001             MOUSE_X_POS = save_mouse_status.x;
2002             MOUSE_Y_POS = save_mouse_status.y;
2003             BUTTON_STATUS(button_no) = BUTTON_DOUBLE_CLICKED;
2004 
2005             _selection_off();
2006             remove_release = True;
2007         }
2008         else
2009         {
2010             napms(SP->mouse_wait);
2011             event->type = ButtonRelease;
2012             XSendEvent(event->xbutton.display, event->xbutton.window,
2013                        True, 0, event);
2014             last_button_press_time = event->xbutton.time;
2015 
2016             return;
2017         }
2018 
2019         last_button_press_time = event->xbutton.time;
2020         break;
2021 
2022     case MotionNotify:
2023         MOUSE_LOG(("\nMotionNotify: y: %d x: %d Width: %d "
2024                    "Height: %d\n", event->xbutton.y, event->xbutton.x,
2025                    font_width, font_height));
2026 
2027         MOUSE_X_POS = (event->xbutton.x - xc_app_data.borderWidth) /
2028                       font_width;
2029         MOUSE_Y_POS = (event->xbutton.y - xc_app_data.borderWidth) /
2030                       font_height;
2031 
2032         if (button_no == 1 &&
2033             (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2034         {
2035             _selection_extend(MOUSE_X_POS, MOUSE_Y_POS);
2036             send_key = FALSE;
2037         }
2038         else
2039             _selection_off();
2040 
2041         /* Throw away mouse movements if they are in the same character
2042            position as the last mouse event, or if we are currently in
2043            the middle of a double click event. */
2044 
2045         if ((MOUSE_X_POS == save_mouse_status.x &&
2046              MOUSE_Y_POS == save_mouse_status.y) ||
2047              save_mouse_status.button[button_no - 1] == BUTTON_DOUBLE_CLICKED)
2048         {
2049             send_key = FALSE;
2050             break;
2051         }
2052 
2053         Mouse_status.changes |= PDC_MOUSE_MOVED;
2054         break;
2055 
2056     case ButtonRelease:
2057         if (remove_release)
2058         {
2059             MOUSE_LOG(("Release at: %ld - removed\n", event->xbutton.time));
2060             return;
2061         }
2062         else
2063         {
2064             MOUSE_X_POS = (event->xbutton.x - xc_app_data.borderWidth) /
2065                           font_width;
2066             MOUSE_Y_POS = (event->xbutton.y - xc_app_data.borderWidth) /
2067                           font_height;
2068 
2069             if (!handle_real_release)
2070             {
2071                 if ((event->xbutton.time - last_button_press_time) <
2072                     SP->mouse_wait &&
2073                     (event->xbutton.time != last_button_press_time))
2074                 {
2075                     /* The "real" release was shorter than usleep() time;
2076                        therefore generate a click event */
2077 
2078                     MOUSE_LOG(("Release at: %ld - click\n",
2079                                event->xbutton.time));
2080 
2081                     BUTTON_STATUS(button_no) = BUTTON_CLICKED;
2082 
2083                     if (button_no == 1 && mouse_selection &&
2084                         (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2085                     {
2086                         send_key = FALSE;
2087 
2088                         if (XtOwnSelection(topLevel, XA_PRIMARY,
2089                                            event->xbutton.time, _convert_proc,
2090                                            _lose_ownership, NULL) == False)
2091                             _selection_off();
2092                     }
2093                     else
2094                         _selection_off();
2095 
2096                     /* Ensure the "pseudo" release event is ignored */
2097 
2098                     remove_release = True;
2099                     handle_real_release = False;
2100                     break;
2101                 }
2102                 else
2103                 {
2104                     /* Button release longer than usleep() time;
2105                        therefore generate a press and wait for the real
2106                        release to occur later. */
2107 
2108                     MOUSE_LOG(("Generated Release at: %ld - "
2109                                "press & release\n", event->xbutton.time));
2110 
2111                     BUTTON_STATUS(button_no) = BUTTON_PRESSED;
2112 
2113                     if (button_no == 1 &&
2114                         (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2115                     {
2116                         _selection_off();
2117                         _selection_on(MOUSE_X_POS, MOUSE_Y_POS);
2118                     }
2119 
2120                     handle_real_release = True;
2121                     break;
2122                 }
2123             }
2124             else
2125             {
2126                 MOUSE_LOG(("Release at: %ld - released\n",
2127                            event->xbutton.time));
2128             }
2129         }
2130 
2131         MOUSE_LOG(("\nButtonRelease\n"));
2132 
2133         BUTTON_STATUS(button_no) = BUTTON_RELEASED;
2134 
2135         if (button_no == 1 && mouse_selection &&
2136             (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2137         {
2138             send_key = FALSE;
2139 
2140             if (XtOwnSelection(topLevel, XA_PRIMARY,
2141                                event->xbutton.time, _convert_proc,
2142                                _lose_ownership, NULL) == False)
2143                 _selection_off();
2144 
2145             _selection_set();
2146         }
2147         else
2148             _selection_off();
2149 
2150         break;
2151     }
2152 
2153     /* Set up the mouse status fields in preparation for sending */
2154 
2155     Mouse_status.changes |= 1 << (button_no - 1);
2156 
2157     if (Mouse_status.changes & PDC_MOUSE_MOVED &&
2158         BUTTON_STATUS(button_no) == BUTTON_PRESSED)
2159         BUTTON_STATUS(button_no) = BUTTON_MOVED;
2160 
2161     if (event->xbutton.state & ShiftMask)
2162         BUTTON_STATUS(button_no) |= BUTTON_SHIFT;
2163     if (event->xbutton.state & ControlMask)
2164         BUTTON_STATUS(button_no) |= BUTTON_CONTROL;
2165     if (event->xbutton.state & Mod1Mask)
2166         BUTTON_STATUS(button_no) |= BUTTON_ALT;
2167 
2168     /* If we are ignoring the event, or the mouse position is outside
2169        the bounds of the screen (because of the border), return here */
2170 
2171     MOUSE_LOG(("Button: %d x: %d y: %d Button status: %x "
2172         "Mouse status: %x\n", button_no, MOUSE_X_POS, MOUSE_Y_POS,
2173         BUTTON_STATUS(button_no), Mouse_status.changes));
2174 
2175     MOUSE_LOG(("Send: %d Button1: %x Button2: %x Button3: %x %d %d\n",
2176         send_key, BUTTON_STATUS(1), BUTTON_STATUS(2),
2177         BUTTON_STATUS(3), XCursesLINES, XCursesCOLS));
2178 
2179     if (!send_key || MOUSE_X_POS < 0 || MOUSE_X_POS >= XCursesCOLS ||
2180         MOUSE_Y_POS < 0 || MOUSE_Y_POS >= XCursesLINES)
2181         return;
2182 
2183     /* Send the KEY_MOUSE to curses program */
2184 
2185     _send_key_to_curses(KEY_MOUSE, &Mouse_status, TRUE);
2186 }
2187 
_scroll_up_down(Widget w,XtPointer client_data,XtPointer call_data)2188 static void _scroll_up_down(Widget w, XtPointer client_data,
2189                             XtPointer call_data)
2190 {
2191     int pixels = (long) call_data;
2192     int total_y = SP->sb_total_y * font_height;
2193     int viewport_y = SP->sb_viewport_y * font_height;
2194     int cur_y = SP->sb_cur_y * font_height;
2195 
2196     /* When pixels is negative, right button pressed, move data down,
2197        thumb moves up.  Otherwise, left button pressed, pixels positive,
2198        move data up, thumb down. */
2199 
2200     cur_y += pixels;
2201 
2202     /* limit panning to size of overall */
2203 
2204     if (cur_y < 0)
2205         cur_y = 0;
2206     else
2207         if (cur_y > (total_y - viewport_y))
2208             cur_y = total_y - viewport_y;
2209 
2210     SP->sb_cur_y = cur_y / font_height;
2211 
2212     XawScrollbarSetThumb(w, (double)((double)cur_y / (double)total_y),
2213                          (double)((double)viewport_y / (double)total_y));
2214 
2215     /* Send a key: if pixels negative, send KEY_SCROLL_DOWN */
2216 
2217     _send_key_to_curses(KEY_SF, NULL, TRUE);
2218 }
2219 
_scroll_left_right(Widget w,XtPointer client_data,XtPointer call_data)2220 static void _scroll_left_right(Widget w, XtPointer client_data,
2221                                XtPointer call_data)
2222 {
2223     int pixels = (long) call_data;
2224     int total_x = SP->sb_total_x * font_width;
2225     int viewport_x = SP->sb_viewport_x * font_width;
2226     int cur_x = SP->sb_cur_x * font_width;
2227 
2228     cur_x += pixels;
2229 
2230     /* limit panning to size of overall */
2231 
2232     if (cur_x < 0)
2233         cur_x = 0;
2234     else
2235         if (cur_x > (total_x - viewport_x))
2236             cur_x = total_x - viewport_x;
2237 
2238     SP->sb_cur_x = cur_x / font_width;
2239 
2240     XawScrollbarSetThumb(w, (double)((double)cur_x / (double)total_x),
2241                          (double)((double)viewport_x / (double)total_x));
2242 
2243     _send_key_to_curses(KEY_SR, NULL, TRUE);
2244 }
2245 
_thumb_up_down(Widget w,XtPointer client_data,XtPointer call_data)2246 static void _thumb_up_down(Widget w, XtPointer client_data,
2247                            XtPointer call_data)
2248 {
2249     double percent = *(double *) call_data;
2250     double total_y = (double)SP->sb_total_y;
2251     double viewport_y = (double)SP->sb_viewport_y;
2252     int cur_y = SP->sb_cur_y;
2253 
2254     /* If the size of the viewport is > overall area simply return,
2255        as no scrolling is permitted. */
2256 
2257     if (SP->sb_viewport_y >= SP->sb_total_y)
2258         return;
2259 
2260     if ((SP->sb_cur_y = (int)((double)total_y * percent)) >=
2261         (total_y - viewport_y))
2262         SP->sb_cur_y = total_y - viewport_y;
2263 
2264     XawScrollbarSetThumb(w, (double)(cur_y / total_y),
2265                          (double)(viewport_y / total_y));
2266 
2267     _send_key_to_curses(KEY_SF, NULL, TRUE);
2268 }
2269 
_thumb_left_right(Widget w,XtPointer client_data,XtPointer call_data)2270 static void _thumb_left_right(Widget w, XtPointer client_data,
2271                   XtPointer call_data)
2272 {
2273     double percent = *(double *) call_data;
2274     double total_x = (double)SP->sb_total_x;
2275     double viewport_x = (double)SP->sb_viewport_x;
2276     int cur_x = SP->sb_cur_x;
2277 
2278     if (SP->sb_viewport_x >= SP->sb_total_x)
2279         return;
2280 
2281     if ((SP->sb_cur_x = (int)((float)total_x * percent)) >=
2282         (total_x - viewport_x))
2283         SP->sb_cur_x = total_x - viewport_x;
2284 
2285     XawScrollbarSetThumb(w, (double)(cur_x / total_x),
2286                          (double)(viewport_x / total_x));
2287 
2288     _send_key_to_curses(KEY_SR, NULL, TRUE);
2289 }
2290 
_exit_process(int rc,int sig,char * msg)2291 static void _exit_process(int rc, int sig, char *msg)
2292 {
2293     if (rc || sig)
2294         fprintf(stderr, "%s:_exit_process() - called: rc:%d sig:%d <%s>\n",
2295                 XCLOGMSG, rc, sig, msg);
2296 
2297     shmdt((char *)SP);
2298     shmdt((char *)Xcurscr);
2299     shmctl(shmidSP, IPC_RMID, 0);
2300     shmctl(shmid_Xcurscr, IPC_RMID, 0);
2301 
2302     if (bitmap_file)
2303     {
2304         XFreePixmap(XCURSESDISPLAY, icon_bitmap);
2305         free(bitmap_file);
2306     }
2307 
2308 #ifdef HAVE_XPM_H
2309     if (pixmap_file)
2310     {
2311         XFreePixmap(XCURSESDISPLAY, icon_pixmap);
2312         XFreePixmap(XCURSESDISPLAY, icon_pixmap_mask);
2313         free(pixmap_file);
2314     }
2315 #endif
2316     XFreeGC(XCURSESDISPLAY, normal_gc);
2317     XFreeGC(XCURSESDISPLAY, italic_gc);
2318     XFreeGC(XCURSESDISPLAY, block_cursor_gc);
2319     XFreeGC(XCURSESDISPLAY, rect_cursor_gc);
2320     XFreeGC(XCURSESDISPLAY, border_gc);
2321 #ifdef PDC_XIM
2322     XDestroyIC(Xic);
2323 #endif
2324 
2325     shutdown(xc_display_sock, 2);
2326     close(xc_display_sock);
2327 
2328     shutdown(xc_exit_sock, 2);
2329     close(xc_exit_sock);
2330 
2331     shutdown(xc_key_sock, 2);
2332     close(xc_key_sock);
2333 
2334     if (sig)
2335         kill(xc_otherpid, sig); /* to kill parent process */
2336 
2337     _exit(rc);
2338 }
2339 
_resize(void)2340 static void _resize(void)
2341 {
2342     short save_atrtab[PDC_COLOR_PAIRS * 2];
2343 
2344     after_first_curses_request = FALSE;
2345 
2346     SP->lines = XCursesLINES = ((resize_window_height -
2347         (2 * xc_app_data.borderWidth)) / font_height);
2348 
2349     LINES = XCursesLINES - SP->linesrippedoff - SP->slklines;
2350 
2351     SP->cols = COLS = XCursesCOLS = ((resize_window_width -
2352         (2 * xc_app_data.borderWidth)) / font_width);
2353 
2354     window_width = resize_window_width;
2355     window_height = resize_window_height;
2356     visible_cursor = TRUE;
2357 
2358     _draw_border();
2359 
2360     /* Detach and drop the current shared memory segment and create and
2361        attach to a new segment */
2362 
2363     memcpy(save_atrtab, xc_atrtab, sizeof(save_atrtab));
2364 
2365     SP->XcurscrSize = XCURSCR_SIZE;
2366     shmdt((char *)Xcurscr);
2367     shmctl(shmid_Xcurscr, IPC_RMID, 0);
2368 
2369     if ((shmid_Xcurscr = shmget(shmkey_Xcurscr,
2370         SP->XcurscrSize + XCURSESSHMMIN, 0700 | IPC_CREAT)) < 0)
2371     {
2372         perror("Cannot allocate shared memory for curscr");
2373 
2374         _exit_process(4, SIGKILL, "exiting from _process_curses_requests");
2375     }
2376 
2377     Xcurscr = (unsigned char*)shmat(shmid_Xcurscr, 0, 0);
2378     memset(Xcurscr, 0, SP->XcurscrSize);
2379     xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF);
2380     memcpy(xc_atrtab, save_atrtab, sizeof(save_atrtab));
2381 }
2382 
2383 /* For PDC_set_title() */
2384 
_set_title(void)2385 static void _set_title(void)
2386 {
2387     char title[1024];   /* big enough for window title */
2388     int pos;
2389 
2390     if ((XC_read_socket(xc_display_sock, &pos, sizeof(int)) < 0) ||
2391         (XC_read_socket(xc_display_sock, title, pos) < 0))
2392     {
2393         _exit_process(5, SIGKILL, "exiting from _set_title");
2394     }
2395 
2396     XtVaSetValues(topLevel, XtNtitle, title, NULL);
2397 }
2398 
2399 /* For color_content() */
2400 
_get_color(void)2401 static void _get_color(void)
2402 {
2403     XColor *tmp = (XColor *)(Xcurscr + XCURSCR_XCOLOR_OFF);
2404     int index = tmp->pixel;
2405     Colormap cmap = DefaultColormap(XCURSESDISPLAY,
2406                                     DefaultScreen(XCURSESDISPLAY));
2407 
2408     if (index < 0 || index >= MAX_COLORS)
2409         _exit_process(4, SIGKILL, "exiting from _get_color");
2410 
2411     tmp->pixel = colors[index];
2412     XQueryColor(XCURSESDISPLAY, cmap, tmp);
2413 }
2414 
2415 /* For init_color() */
2416 
_set_color(void)2417 static void _set_color(void)
2418 {
2419     XColor *tmp = (XColor *)(Xcurscr + XCURSCR_XCOLOR_OFF);
2420     int index = tmp->pixel;
2421     Colormap cmap = DefaultColormap(XCURSESDISPLAY,
2422                                     DefaultScreen(XCURSESDISPLAY));
2423 
2424     if (index < 0 || index >= MAX_COLORS)
2425         _exit_process(4, SIGKILL, "exiting from _set_color");
2426 
2427     if (XAllocColor(XCURSESDISPLAY, cmap, tmp))
2428     {
2429         XFreeColors(XCURSESDISPLAY, cmap, colors + index, 1, 0);
2430         colors[index] = tmp->pixel;
2431 
2432         _display_screen();
2433     }
2434 }
2435 
2436 /* For PDC_getclipboard() */
2437 
_get_selection(Widget w,XtPointer data,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)2438 static void _get_selection(Widget w, XtPointer data, Atom *selection,
2439                            Atom *type, XtPointer value,
2440                            unsigned long *length, int *format)
2441 {
2442     unsigned char *src = value;
2443     int pos, len = *length;
2444 
2445     XC_LOG(("_get_selection() - called\n"));
2446 
2447     if (!value && !len)
2448     {
2449         if (XC_write_display_socket_int(PDC_CLIP_EMPTY) < 0)
2450             _exit_process(4, SIGKILL, "exiting from _get_selection");
2451     }
2452     else
2453     {
2454         /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then
2455            contents */
2456 
2457         if (XC_write_display_socket_int(PDC_CLIP_SUCCESS) < 0)
2458             _exit_process(4, SIGKILL, "exiting from _get_selection");
2459 
2460         if (XC_write_display_socket_int(len) < 0)
2461             _exit_process(4, SIGKILL, "exiting from _get_selection");
2462 
2463         for (pos = 0; pos < len; pos++)
2464         {
2465 #ifdef PDC_WIDE
2466             wchar_t c;
2467 #else
2468             unsigned char c;
2469 #endif
2470             c = *src++;
2471 
2472             if (XC_write_socket(xc_display_sock, &c, sizeof(c)) < 0)
2473                 _exit_process(4, SIGKILL, "exiting from _get_selection");
2474         }
2475     }
2476 }
2477 
2478 #ifdef PDC_WIDE
_get_selection_utf8(Widget w,XtPointer data,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)2479 static void _get_selection_utf8(Widget w, XtPointer data, Atom *selection,
2480                                 Atom *type, XtPointer value,
2481                                 unsigned long *length, int *format)
2482 {
2483     int len = *length;
2484 
2485     XC_LOG(("_get_selection_utf8() - called\n"));
2486 
2487     if (!*type || !*length)
2488     {
2489         XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _get_selection,
2490                             (XtPointer)NULL, 0);
2491         return;
2492     }
2493 
2494     if (!value && !len)
2495     {
2496         if (XC_write_display_socket_int(PDC_CLIP_EMPTY) >= 0)
2497             return;
2498     }
2499     else
2500     {
2501         wchar_t *wcontents = malloc((len + 1) * sizeof(wchar_t));
2502         char *src = value;
2503         int i = 0;
2504 
2505         while (*src && i < (*length))
2506         {
2507             int retval = _from_utf8(wcontents + i, src, len);
2508 
2509             src += retval;
2510             len -= retval;
2511             i++;
2512         }
2513 
2514         wcontents[i] = 0;
2515         len = i;
2516 
2517         /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then
2518            contents */
2519 
2520         if (XC_write_display_socket_int(PDC_CLIP_SUCCESS) >= 0)
2521             if (XC_write_display_socket_int(len) >= 0)
2522                 if (XC_write_socket(xc_display_sock,
2523                     wcontents, len * sizeof(wchar_t)) >= 0)
2524                 {
2525                     free(wcontents);
2526                     return;
2527                 }
2528     }
2529 
2530     _exit_process(4, SIGKILL, "exiting from _get_selection_utf8");
2531 }
2532 #endif
2533 
2534 /* For PDC_setclipboard() */
2535 
_set_selection(void)2536 static void _set_selection(void)
2537 {
2538     long length, pos;
2539     int status;
2540 
2541     if (XC_read_socket(xc_display_sock, &length, sizeof(long)) < 0)
2542         _exit_process(5, SIGKILL, "exiting from _set_selection");
2543 
2544     if (length > (long)tmpsel_length)
2545     {
2546         if (!tmpsel_length)
2547             tmpsel = malloc((length + 1) * sizeof(chtype));
2548         else
2549             tmpsel = realloc(tmpsel, (length + 1) * sizeof(chtype));
2550     }
2551 
2552     if (!tmpsel)
2553         if (XC_write_display_socket_int(PDC_CLIP_MEMORY_ERROR) < 0)
2554             _exit_process(4, SIGKILL, "exiting from _set_selection");
2555 
2556     for (pos = 0; pos < length; pos++)
2557     {
2558 #ifdef PDC_WIDE
2559         wchar_t c;
2560 #else
2561         unsigned char c;
2562 #endif
2563         if (XC_read_socket(xc_display_sock, &c, sizeof(c)) < 0)
2564             _exit_process(5, SIGKILL, "exiting from _set_selection");
2565 
2566         tmpsel[pos] = c;
2567     }
2568 
2569     tmpsel_length = length;
2570     tmpsel[length] = 0;
2571 
2572     if (XtOwnSelection(topLevel, XA_PRIMARY, CurrentTime,
2573                        _convert_proc, _lose_ownership, NULL) == False)
2574     {
2575         status = PDC_CLIP_ACCESS_ERROR;
2576         free(tmpsel);
2577         tmpsel = NULL;
2578         tmpsel_length = 0;
2579     }
2580     else
2581         status = PDC_CLIP_SUCCESS;
2582 
2583     _selection_off();
2584 
2585     if (XC_write_display_socket_int(status) < 0)
2586         _exit_process(4, SIGKILL, "exiting from _set_selection");
2587 }
2588 
2589 /* The curses process is waiting; tell it to continue */
2590 
_resume_curses(void)2591 static void _resume_curses(void)
2592 {
2593     if (XC_write_display_socket_int(CURSES_CONTINUE) < 0)
2594         _exit_process(4, SIGKILL, "exiting from _process_curses_requests");
2595 }
2596 
2597 /* The curses process sent us a message */
2598 
_process_curses_requests(XtPointer client_data,int * fid,XtInputId * id)2599 static void _process_curses_requests(XtPointer client_data, int *fid,
2600                                      XtInputId *id)
2601 {
2602     struct timeval socket_timeout = {0};
2603     int s;
2604     int old_row, new_row;
2605     int old_x, new_x;
2606     int pos, num_cols;
2607 
2608     char buf[12];       /* big enough for 2 integers */
2609 
2610     XC_LOG(("_process_curses_requests() - called\n"));
2611 
2612     if (!received_map_notify)
2613         return;
2614 
2615     FD_ZERO(&xc_readfds);
2616     FD_SET(xc_display_sock, &xc_readfds);
2617 
2618     if ((s = select(FD_SETSIZE, (FD_SET_CAST)&xc_readfds, NULL,
2619                     NULL, &socket_timeout)) < 0)
2620         _exit_process(2, SIGKILL, "exiting from _process_curses_requests"
2621                                   " - select failed");
2622 
2623     if (!s)     /* no requests pending - should never happen! */
2624         return;
2625 
2626     if (FD_ISSET(xc_display_sock, &xc_readfds))
2627     {
2628         /* read first integer to determine total message has been
2629            received */
2630 
2631         XC_LOG(("_process_curses_requests() - before XC_read_socket()\n"));
2632 
2633         if (XC_read_socket(xc_display_sock, &num_cols, sizeof(int)) < 0)
2634             _exit_process(3, SIGKILL, "exiting from _process_curses_requests"
2635                                       " - first read");
2636 
2637         XC_LOG(("_process_curses_requests() - after XC_read_socket()\n"));
2638 
2639         after_first_curses_request = TRUE;
2640 
2641         switch(num_cols)
2642         {
2643         case CURSES_EXIT:   /* request from curses to stop */
2644             XC_LOG(("CURSES_EXIT received from child\n"));
2645             _exit_process(0, 0, "XCursesProcess requested to exit by child");
2646             break;
2647 
2648         case CURSES_BELL:
2649             XC_LOG(("CURSES_BELL received from child\n"));
2650             XBell(XCURSESDISPLAY, 50);
2651             break;
2652 
2653         /* request from curses to confirm completion of display */
2654 
2655         case CURSES_REFRESH:
2656             XC_LOG(("CURSES_REFRESH received from child\n"));
2657             _refresh_screen();
2658             _resume_curses();
2659             break;
2660 
2661         case CURSES_REFRESH_SCROLLBAR:
2662             _refresh_scrollbar();
2663             break;
2664 
2665         case CURSES_CURSOR:
2666             XC_LOG(("CURSES_CURSOR received from child\n"));
2667 
2668             if (XC_read_socket(xc_display_sock, buf, sizeof(int) * 2) < 0)
2669                 _exit_process(5, SIGKILL, "exiting from CURSES_CURSOR "
2670                                           "_process_curses_requests");
2671 
2672             memcpy(&pos, buf, sizeof(int));
2673             old_row = pos & 0xFF;
2674             old_x = pos >> 8;
2675 
2676             memcpy(&pos, buf + sizeof(int), sizeof(int));
2677             new_row = pos & 0xFF;
2678             new_x = pos >> 8;
2679 
2680             visible_cursor = TRUE;
2681             _display_cursor(old_row, old_x, new_row, new_x);
2682             break;
2683 
2684         case CURSES_DISPLAY_CURSOR:
2685             XC_LOG(("CURSES_DISPLAY_CURSOR received from child. Vis now: "));
2686             XC_LOG((visible_cursor ? "1\n" : "0\n"));
2687 
2688             /* If the window is not active, ignore this command. The
2689                cursor will stay solid. */
2690 
2691             if (window_entered)
2692             {
2693                 if (visible_cursor)
2694                 {
2695                     /* Cursor currently ON, turn it off */
2696 
2697                     int save_visibility = SP->visibility;
2698                     SP->visibility = 0;
2699                     _redraw_cursor();
2700                     SP->visibility = save_visibility;
2701                     visible_cursor = FALSE;
2702                 }
2703                 else
2704                 {
2705                     /* Cursor currently OFF, turn it on */
2706 
2707                     _redraw_cursor();
2708                     visible_cursor = TRUE;
2709                 }
2710             }
2711 
2712             break;
2713 
2714         case CURSES_TITLE:
2715             XC_LOG(("CURSES_TITLE received from child\n"));
2716             _set_title();
2717             break;
2718 
2719         case CURSES_RESIZE:
2720             XC_LOG(("CURSES_RESIZE received from child\n"));
2721             _resize();
2722             _resume_curses();
2723             break;
2724 
2725         case CURSES_GET_SELECTION:
2726             XC_LOG(("CURSES_GET_SELECTION received from child\n"));
2727 
2728             _resume_curses();
2729 
2730             XtGetSelectionValue(topLevel, XA_PRIMARY,
2731 #ifdef PDC_WIDE
2732                                 XA_UTF8_STRING(XtDisplay(topLevel)),
2733                                 _get_selection_utf8,
2734 #else
2735                                 XA_STRING, _get_selection,
2736 #endif
2737                                 (XtPointer)NULL, 0);
2738 
2739             break;
2740 
2741         case CURSES_SET_SELECTION:
2742             XC_LOG(("CURSES_SET_SELECTION received from child\n"));
2743             _set_selection();
2744             break;
2745 
2746         case CURSES_CLEAR_SELECTION:
2747             XC_LOG(("CURSES_CLEAR_SELECTION received from child\n"));
2748             _resume_curses();
2749             _selection_off();
2750             break;
2751 
2752         case CURSES_GET_COLOR:
2753             XC_LOG(("CURSES_GET_COLOR recieved from child\n"));
2754             _get_color();
2755             _resume_curses();
2756             break;
2757 
2758         case CURSES_SET_COLOR:
2759             XC_LOG(("CURSES_SET_COLOR recieved from child\n"));
2760             _set_color();
2761             _resume_curses();
2762             break;
2763 
2764         default:
2765             PDC_LOG(("%s:Unknown request %d\n", XCLOGMSG, num_cols));
2766         }
2767     }
2768 }
2769 
_handle_structure_notify(Widget w,XtPointer client_data,XEvent * event,Boolean * unused)2770 static void _handle_structure_notify(Widget w, XtPointer client_data,
2771                                      XEvent *event, Boolean *unused)
2772 {
2773     XC_LOG(("_handle_structure_notify() - called\n"));
2774 
2775     switch(event->type)
2776     {
2777     case ConfigureNotify:
2778         XC_LOG(("ConfigureNotify received\n"));
2779 
2780         /* Window has been resized, change width and height to send to
2781            place_text and place_graphics in next Expose. Also will need
2782            to kill (SIGWINCH) curses process if screen size changes. */
2783 
2784         resize_window_width = event->xconfigure.width;
2785         resize_window_height = event->xconfigure.height;
2786 
2787         after_first_curses_request = FALSE;
2788 
2789 #ifdef SIGWINCH
2790         SP->resized = 1;
2791 
2792         kill(xc_otherpid, SIGWINCH);
2793 #endif
2794         _send_key_to_curses(KEY_RESIZE, NULL, TRUE);
2795         break;
2796 
2797     case MapNotify:
2798         XC_LOG(("MapNotify received\n"));
2799 
2800         received_map_notify = 1;
2801 
2802         _draw_border();
2803         break;
2804 
2805     default:
2806         PDC_LOG(("%s:_handle_structure_notify - unknown event %d\n",
2807                  XCLOGMSG, event->type));
2808     }
2809 }
2810 
_handle_signals(int signo)2811 static RETSIGTYPE _handle_signals(int signo)
2812 {
2813     int flag = CURSES_EXIT;
2814 
2815     PDC_LOG(("%s:_handle_signals() - called: %d\n", XCLOGMSG, signo));
2816 
2817     /* Patch by: Georg Fuchs */
2818 
2819     XCursesSetSignal(signo, _handle_signals);
2820 
2821 #ifdef SIGTSTP
2822     if (signo == SIGTSTP)
2823     {
2824         pause();
2825         return;
2826     }
2827 #endif
2828 #ifdef SIGCONT
2829     if (signo == SIGCONT)
2830         return;
2831 #endif
2832 #ifdef SIGCLD
2833     if (signo == SIGCLD)
2834         return;
2835 #endif
2836 #ifdef SIGTTIN
2837     if (signo == SIGTTIN)
2838         return;
2839 #endif
2840 #ifdef SIGWINCH
2841     if (signo == SIGWINCH)
2842         return;
2843 #endif
2844 
2845     /* End of patch by: Georg Fuchs */
2846 
2847     XCursesSetSignal(signo, SIG_IGN);
2848 
2849     /* Send a CURSES_EXIT to myself */
2850 
2851     if (XC_write_socket(xc_exit_sock, &flag, sizeof(int)) < 0)
2852         _exit_process(7, signo, "exiting from _handle_signals");
2853 }
2854 
2855 #ifdef PDC_XIM
_dummy_handler(Widget w,XtPointer client_data,XEvent * event,Boolean * unused)2856 static void _dummy_handler(Widget w, XtPointer client_data,
2857                            XEvent *event, Boolean *unused)
2858 {
2859 }
2860 #endif
2861 
XCursesSetupX(int argc,char * argv[])2862 int XCursesSetupX(int argc, char *argv[])
2863 {
2864     char *myargv[] = {"PDCurses", NULL};
2865     extern bool sb_started;
2866 
2867     int italic_font_valid;
2868     XColor pointerforecolor, pointerbackcolor;
2869     XrmValue rmfrom, rmto;
2870     int i = 0;
2871     int minwidth, minheight;
2872 
2873     XC_LOG(("XCursesSetupX called\n"));
2874 
2875     if (!argv)
2876     {
2877         argv = myargv;
2878         argc = 1;
2879     }
2880 
2881     program_name = argv[0];
2882 
2883     /* Keep open the 'write' end of the socket so the XCurses process
2884        can send a CURSES_EXIT to itself from within the signal handler */
2885 
2886     xc_exit_sock = xc_display_sockets[0];
2887     xc_display_sock = xc_display_sockets[1];
2888 
2889     close(xc_key_sockets[0]);
2890     xc_key_sock = xc_key_sockets[1];
2891 
2892     /* Trap all signals when XCurses is the child process, but only if
2893        they haven't already been ignored by the application. */
2894 
2895     for (i = 0; i < PDC_MAX_SIGNALS; i++)
2896         if (XCursesSetSignal(i, _handle_signals) == SIG_IGN)
2897             XCursesSetSignal(i, SIG_IGN);
2898 
2899     /* Start defining X Toolkit things */
2900 
2901 #if XtSpecificationRelease > 4
2902     XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL);
2903 #endif
2904 
2905     /* Exit if no DISPLAY variable set */
2906 
2907     if (!getenv("DISPLAY"))
2908     {
2909         fprintf(stderr, "Error: no DISPLAY variable set\n");
2910         kill(xc_otherpid, SIGKILL);
2911         return ERR;
2912     }
2913 
2914     /* Initialise the top level widget */
2915 
2916     topLevel = XtVaAppInitialize(&app_context, class_name, options,
2917                                  XtNumber(options), &argc, argv, NULL, NULL);
2918 
2919     XtVaGetApplicationResources(topLevel, &xc_app_data, app_resources,
2920                                 XtNumber(app_resources), NULL);
2921 
2922     /* Check application resource values here */
2923 
2924     font_width = xc_app_data.normalFont->max_bounds.rbearing -
2925                  xc_app_data.normalFont->min_bounds.lbearing;
2926 
2927     font_height = xc_app_data.normalFont->max_bounds.ascent +
2928                   xc_app_data.normalFont->max_bounds.descent;
2929 
2930     font_ascent = xc_app_data.normalFont->max_bounds.ascent;
2931     font_descent = xc_app_data.normalFont->max_bounds.descent;
2932 
2933     /* Check that the italic font and normal fonts are the same size */
2934     /* This appears backwards */
2935 
2936     italic_font_valid = font_width !=
2937         xc_app_data.italicFont->max_bounds.rbearing -
2938         xc_app_data.italicFont->min_bounds.lbearing ||
2939         font_height !=
2940         xc_app_data.italicFont->max_bounds.ascent +
2941         xc_app_data.italicFont->max_bounds.descent;
2942 
2943     /* Calculate size of display window */
2944 
2945     XCursesCOLS = xc_app_data.cols;
2946     XCursesLINES = xc_app_data.lines;
2947 
2948     window_width = font_width * XCursesCOLS +
2949                    2 * xc_app_data.borderWidth;
2950 
2951     window_height = font_height * XCursesLINES +
2952                     2 * xc_app_data.borderWidth;
2953 
2954     minwidth = font_width * 2 + xc_app_data.borderWidth * 2;
2955     minheight = font_height * 2 + xc_app_data.borderWidth * 2;
2956 
2957     /* Set up the icon for the application; the default is an internal
2958        one for PDCurses. Then set various application level resources. */
2959 
2960     _get_icon();
2961 
2962 #ifdef HAVE_XPM_H
2963     if (xc_app_data.pixmap && xc_app_data.pixmap[0])
2964         XtVaSetValues(topLevel, XtNminWidth, minwidth, XtNminHeight,
2965                       minheight, XtNbaseWidth, xc_app_data.borderWidth * 2,
2966                       XtNbaseHeight, xc_app_data.borderWidth * 2,
2967                       XtNiconPixmap, icon_pixmap,
2968                       XtNiconMask, icon_pixmap_mask, NULL);
2969     else
2970 #endif
2971         XtVaSetValues(topLevel, XtNminWidth, minwidth, XtNminHeight,
2972                       minheight, XtNbaseWidth, xc_app_data.borderWidth * 2,
2973                       XtNbaseHeight, xc_app_data.borderWidth * 2,
2974                       XtNiconPixmap, icon_bitmap, NULL);
2975 
2976     /* Create a BOX widget in which to draw */
2977 
2978     if (xc_app_data.scrollbarWidth && sb_started)
2979     {
2980         scrollBox = XtVaCreateManagedWidget(program_name,
2981             scrollBoxWidgetClass, topLevel, XtNwidth,
2982             window_width + xc_app_data.scrollbarWidth,
2983             XtNheight, window_height + xc_app_data.scrollbarWidth,
2984             XtNwidthInc, font_width, XtNheightInc, font_height, NULL);
2985 
2986         drawing = XtVaCreateManagedWidget(program_name,
2987             boxWidgetClass, scrollBox, XtNwidth,
2988             window_width, XtNheight, window_height, XtNwidthInc,
2989             font_width, XtNheightInc, font_height, NULL);
2990 
2991         scrollVert = XtVaCreateManagedWidget("scrollVert",
2992             scrollbarWidgetClass, scrollBox, XtNorientation,
2993             XtorientVertical, XtNheight, window_height, XtNwidth,
2994             xc_app_data.scrollbarWidth, NULL);
2995 
2996         XtAddCallback(scrollVert, XtNscrollProc, _scroll_up_down, drawing);
2997         XtAddCallback(scrollVert, XtNjumpProc, _thumb_up_down, drawing);
2998 
2999         scrollHoriz = XtVaCreateManagedWidget("scrollHoriz",
3000             scrollbarWidgetClass, scrollBox, XtNorientation,
3001             XtorientHorizontal, XtNwidth, window_width, XtNheight,
3002             xc_app_data.scrollbarWidth, NULL);
3003 
3004         XtAddCallback(scrollHoriz, XtNscrollProc, _scroll_left_right, drawing);
3005         XtAddCallback(scrollHoriz, XtNjumpProc, _thumb_left_right, drawing);
3006     }
3007     else
3008     {
3009         drawing = XtVaCreateManagedWidget(program_name, boxWidgetClass,
3010             topLevel, XtNwidth, window_width, XtNheight, window_height,
3011             XtNwidthInc, font_width, XtNheightInc, font_height, NULL);
3012 
3013         XtVaSetValues(topLevel, XtNwidthInc, font_width, XtNheightInc,
3014                       font_height, NULL);
3015     }
3016 
3017     /* Process any default translations */
3018 
3019     XtAugmentTranslations(drawing,
3020                           XtParseTranslationTable(default_translations));
3021     XtAppAddActions(app_context, action_table, XtNumber(action_table));
3022 
3023     /* Process the supplied colors */
3024 
3025     _initialize_colors();
3026 
3027     /* Determine text cursor alignment from resources */
3028 
3029     if (!strcmp(xc_app_data.textCursor, "vertical"))
3030         vertical_cursor = TRUE;
3031 
3032     /* Now have LINES and COLS. Set these in the shared SP so the curses
3033        program can find them. */
3034 
3035     LINES = XCursesLINES;
3036     COLS = XCursesCOLS;
3037 
3038     if ((shmidSP = shmget(shmkeySP, sizeof(SCREEN) + XCURSESSHMMIN,
3039         0700 | IPC_CREAT)) < 0)
3040     {
3041         perror("Cannot allocate shared memory for SCREEN");
3042         kill(xc_otherpid, SIGKILL);
3043         return ERR;
3044     }
3045 
3046     SP = (SCREEN*)shmat(shmidSP, 0, 0);
3047     memset(SP, 0, sizeof(SCREEN));
3048     SP->XcurscrSize = XCURSCR_SIZE;
3049     SP->lines = XCursesLINES;
3050     SP->cols = XCursesCOLS;
3051 
3052     SP->mouse_wait = xc_app_data.clickPeriod;
3053     SP->audible = TRUE;
3054 
3055     PDC_LOG(("%s:SHM size for curscr %d\n", XCLOGMSG, SP->XcurscrSize));
3056 
3057     if ((shmid_Xcurscr = shmget(shmkey_Xcurscr, SP->XcurscrSize +
3058         XCURSESSHMMIN, 0700 | IPC_CREAT)) < 0)
3059     {
3060         perror("Cannot allocate shared memory for curscr");
3061         kill(xc_otherpid, SIGKILL);
3062         shmdt((char *)SP);
3063         shmctl(shmidSP, IPC_RMID, 0);
3064         return ERR;
3065     }
3066 
3067     Xcurscr = (unsigned char *)shmat(shmid_Xcurscr, 0, 0);
3068     memset(Xcurscr, 0, SP->XcurscrSize);
3069     xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF);
3070 
3071     PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n",
3072              XCLOGMSG, shmid_Xcurscr, shmkey_Xcurscr, LINES, COLS));
3073 
3074     /* Add Event handlers to the drawing widget */
3075 
3076     XtAddEventHandler(drawing, ExposureMask, False, _handle_expose, NULL);
3077     XtAddEventHandler(drawing, StructureNotifyMask, False,
3078                       _handle_structure_notify, NULL);
3079     XtAddEventHandler(drawing, EnterWindowMask | LeaveWindowMask, False,
3080                       _handle_enter_leave, NULL);
3081     XtAddEventHandler(topLevel, 0, True, _handle_nonmaskable, NULL);
3082 
3083     /* Add input handler from xc_display_sock (requests from curses
3084        program) */
3085 
3086     XtAppAddInput(app_context, xc_display_sock, (XtPointer)XtInputReadMask,
3087                   _process_curses_requests, NULL);
3088 
3089     /* If there is a cursorBlink resource, start the Timeout event */
3090 
3091     if (xc_app_data.cursorBlinkRate)
3092         XtAppAddTimeOut(app_context, xc_app_data.cursorBlinkRate,
3093                         _blink_cursor, NULL);
3094 
3095     /* Leave telling the curses process that it can start to here so
3096        that when the curses process makes a request, the Xcurses
3097        process can service the request. */
3098 
3099     XC_write_display_socket_int(CURSES_CHILD);
3100 
3101     XtRealizeWidget(topLevel);
3102 
3103     /* Handle trapping of the WM_DELETE_WINDOW property */
3104 
3105     wm_atom[0] = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", False);
3106 
3107     XSetWMProtocols(XtDisplay(topLevel), XtWindow(topLevel), wm_atom, 1);
3108 
3109     /* Create the Graphics Context for drawing. This MUST be done AFTER
3110        the associated widget has been realized. */
3111 
3112     XC_LOG(("before _get_gc\n"));
3113 
3114     _get_gc(&normal_gc, xc_app_data.normalFont, COLOR_WHITE, COLOR_BLACK);
3115 
3116     _get_gc(&italic_gc, italic_font_valid ? xc_app_data.italicFont :
3117             xc_app_data.normalFont, COLOR_WHITE, COLOR_BLACK);
3118 
3119     _get_gc(&block_cursor_gc, xc_app_data.normalFont,
3120             COLOR_BLACK, COLOR_CURSOR);
3121 
3122     _get_gc(&rect_cursor_gc, xc_app_data.normalFont,
3123             COLOR_CURSOR, COLOR_BLACK);
3124 
3125     _get_gc(&border_gc, xc_app_data.normalFont, COLOR_BORDER, COLOR_BLACK);
3126 
3127     XSetLineAttributes(XCURSESDISPLAY, rect_cursor_gc, 2,
3128                        LineSolid, CapButt, JoinMiter);
3129 
3130     XSetLineAttributes(XCURSESDISPLAY, border_gc, xc_app_data.borderWidth,
3131                        LineSolid, CapButt, JoinMiter);
3132 
3133     /* Set the cursor for the application */
3134 
3135     XDefineCursor(XCURSESDISPLAY, XCURSESWIN, xc_app_data.pointer);
3136     rmfrom.size = sizeof(Pixel);
3137     rmto.size = sizeof(XColor);
3138 
3139     rmto.addr = (XPointer)&pointerforecolor;
3140     rmfrom.addr = (XPointer)&(xc_app_data.pointerForeColor);
3141     XtConvertAndStore(drawing, XtRPixel, &rmfrom, XtRColor, &rmto);
3142 
3143     rmfrom.size = sizeof(Pixel);
3144     rmto.size = sizeof(XColor);
3145 
3146     rmfrom.addr = (XPointer)&(xc_app_data.pointerBackColor);
3147     rmto.addr = (XPointer)&pointerbackcolor;
3148     XtConvertAndStore(drawing, XtRPixel, &rmfrom, XtRColor, &rmto);
3149 
3150     XRecolorCursor(XCURSESDISPLAY, xc_app_data.pointer,
3151                    &pointerforecolor, &pointerbackcolor);
3152 
3153 #ifndef PDC_XIM
3154 
3155     /* Convert the supplied compose key to a Keysym */
3156 
3157     compose_key = XStringToKeysym(xc_app_data.composeKey);
3158 
3159     if (compose_key && IsModifierKey(compose_key))
3160     {
3161         int i, j;
3162         KeyCode *kcp;
3163         XModifierKeymap *map;
3164         KeyCode compose_keycode = XKeysymToKeycode(XCURSESDISPLAY, compose_key);
3165 
3166         map = XGetModifierMapping(XCURSESDISPLAY);
3167         kcp = map->modifiermap;
3168 
3169         for (i = 0; i < 8; i++)
3170         {
3171             for (j = 0; j < map->max_keypermod; j++, kcp++)
3172             {
3173                 if (!*kcp)
3174                     continue;
3175 
3176                 if (compose_keycode == *kcp)
3177                 {
3178                     compose_mask = state_mask[i];
3179                     break;
3180                 }
3181             }
3182 
3183             if (compose_mask)
3184                 break;
3185         }
3186 
3187         XFreeModifiermap(map);
3188     }
3189 
3190 #else
3191     Xim = XOpenIM(XCURSESDISPLAY, NULL, NULL, NULL);
3192 
3193     if (Xim)
3194     {
3195         Xic = XCreateIC(Xim, XNInputStyle,
3196                         XIMPreeditNothing | XIMStatusNothing,
3197                         XNClientWindow, XCURSESWIN, NULL);
3198     }
3199 
3200     if (Xic)
3201     {
3202         long im_event_mask;
3203 
3204         XGetICValues(Xic, XNFilterEvents, &im_event_mask, NULL);
3205         if (im_event_mask)
3206             XtAddEventHandler(drawing, im_event_mask, False,
3207                               _dummy_handler, NULL);
3208 
3209         XSetICFocus(Xic);
3210     }
3211     else
3212     {
3213         perror("ERROR: Cannot create input context");
3214         kill(xc_otherpid, SIGKILL);
3215         shmdt((char *)SP);
3216         shmdt((char *)Xcurscr);
3217         shmctl(shmidSP, IPC_RMID, 0);
3218         shmctl(shmid_Xcurscr, IPC_RMID, 0);
3219         return ERR;
3220     }
3221 
3222 #endif
3223 
3224     /* Wait for events */
3225 
3226     XtAppMainLoop(app_context);
3227     return OK;          /* won't get here */
3228 }
3229