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