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