drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / payloads / libpayload / curses / PDCurses / x11 / x11.c
blob46444d4471ca42b9957cf6f420bc002ddfa56e82
1 /* Public Domain Curses */
3 #include "pdcx11.h"
5 RCSID("$Id: x11.c,v 1.94 2008/07/14 04:33:26 wmcbrine Exp $")
7 #ifdef HAVE_DECKEYSYM_H
8 # include <DECkeysym.h>
9 #endif
11 #ifdef HAVE_SUNKEYSYM_H
12 # include <Sunkeysym.h>
13 #endif
15 #ifdef HAVE_XPM_H
16 # include <xpm.h>
17 #endif
19 #if defined PDC_XIM
20 # include <Xlocale.h>
21 #endif
23 #include <stdlib.h>
24 #include <string.h>
26 #ifndef XPOINTER_TYPEDEFED
27 typedef char * XPointer;
28 #endif
30 #ifndef MAX_PATH
31 # define MAX_PATH 256
32 #endif
34 XCursesAppData xc_app_data;
36 #if NeedWidePrototypes
37 # define PDC_SCROLLBAR_TYPE double
38 #else
39 # define PDC_SCROLLBAR_TYPE float
40 #endif
42 #define MAX_COLORS 16 /* maximum of "normal" colors */
43 #define COLOR_CURSOR MAX_COLORS /* color of cursor */
44 #define COLOR_BORDER MAX_COLORS + 1 /* color of border */
46 #define XCURSESDISPLAY (XtDisplay(drawing))
47 #define XCURSESWIN (XtWindow(drawing))
49 /* Default icons for XCurses applications. */
51 #include "big_icon.xbm"
52 #include "little_icon.xbm"
54 static void _selection_off(void);
55 static void _display_cursor(int, int, int, int);
56 static void _redraw_cursor(void);
57 static void _exit_process(int, int, char *);
58 static void _send_key_to_curses(unsigned long, MOUSE_STATUS *, bool);
60 static void XCursesButton(Widget, XEvent *, String *, Cardinal *);
61 static void XCursesHandleString(Widget, XEvent *, String *, Cardinal *);
62 static void XCursesKeyPress(Widget, XEvent *, String *, Cardinal *);
63 static void XCursesPasteSelection(Widget, XButtonEvent *);
65 static struct
67 KeySym keycode;
68 bool numkeypad;
69 unsigned short normal;
70 unsigned short shifted;
71 unsigned short control;
72 unsigned short alt;
73 } key_table[] =
75 /* keycode keypad normal shifted control alt*/
76 {XK_Left, FALSE, KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT},
77 {XK_Right, FALSE, KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT},
78 {XK_Up, FALSE, KEY_UP, KEY_SUP, CTL_UP, ALT_UP},
79 {XK_Down, FALSE, KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN},
80 {XK_Home, FALSE, KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME},
81 /* Sun Type 4 keyboard */
82 {XK_R7, FALSE, KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME},
83 {XK_End, FALSE, KEY_END, KEY_SEND, CTL_END, ALT_END},
84 /* Sun Type 4 keyboard */
85 {XK_R13, FALSE, KEY_END, KEY_SEND, CTL_END, ALT_END},
86 {XK_Prior, FALSE, KEY_PPAGE, KEY_SPREVIOUS,CTL_PGUP, ALT_PGUP},
87 /* Sun Type 4 keyboard */
88 {XK_R9, FALSE, KEY_PPAGE, KEY_SPREVIOUS,CTL_PGUP, ALT_PGUP},
89 {XK_Next, FALSE, KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN},
90 /* Sun Type 4 keyboard */
91 {XK_R15, FALSE, KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN},
92 {XK_Insert, FALSE, KEY_IC, KEY_SIC, CTL_INS, ALT_INS},
93 {XK_Delete, FALSE, KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL},
94 {XK_F1, FALSE, KEY_F(1), KEY_F(13), KEY_F(25), KEY_F(37)},
95 {XK_F2, FALSE, KEY_F(2), KEY_F(14), KEY_F(26), KEY_F(38)},
96 {XK_F3, FALSE, KEY_F(3), KEY_F(15), KEY_F(27), KEY_F(39)},
97 {XK_F4, FALSE, KEY_F(4), KEY_F(16), KEY_F(28), KEY_F(40)},
98 {XK_F5, FALSE, KEY_F(5), KEY_F(17), KEY_F(29), KEY_F(41)},
99 {XK_F6, FALSE, KEY_F(6), KEY_F(18), KEY_F(30), KEY_F(42)},
100 {XK_F7, FALSE, KEY_F(7), KEY_F(19), KEY_F(31), KEY_F(43)},
101 {XK_F8, FALSE, KEY_F(8), KEY_F(20), KEY_F(32), KEY_F(44)},
102 {XK_F9, FALSE, KEY_F(9), KEY_F(21), KEY_F(33), KEY_F(45)},
103 {XK_F10, FALSE, KEY_F(10), KEY_F(22), KEY_F(34), KEY_F(46)},
104 {XK_F11, FALSE, KEY_F(11), KEY_F(23), KEY_F(35), KEY_F(47)},
105 {XK_F12, FALSE, KEY_F(12), KEY_F(24), KEY_F(36), KEY_F(48)},
106 {XK_F13, FALSE, KEY_F(13), KEY_F(25), KEY_F(37), KEY_F(49)},
107 {XK_F14, FALSE, KEY_F(14), KEY_F(26), KEY_F(38), KEY_F(50)},
108 {XK_F15, FALSE, KEY_F(15), KEY_F(27), KEY_F(39), KEY_F(51)},
109 {XK_F16, FALSE, KEY_F(16), KEY_F(28), KEY_F(40), KEY_F(52)},
110 {XK_F17, FALSE, KEY_F(17), KEY_F(29), KEY_F(41), KEY_F(53)},
111 {XK_F18, FALSE, KEY_F(18), KEY_F(30), KEY_F(42), KEY_F(54)},
112 {XK_F19, FALSE, KEY_F(19), KEY_F(31), KEY_F(43), KEY_F(55)},
113 {XK_F20, FALSE, KEY_F(20), KEY_F(32), KEY_F(44), KEY_F(56)},
114 {XK_BackSpace, FALSE, 0x08, 0x08, CTL_BKSP, ALT_BKSP},
115 {XK_Tab, FALSE, 0x09, KEY_BTAB, CTL_TAB, ALT_TAB},
116 {XK_Select, FALSE, KEY_SELECT, KEY_SELECT, KEY_SELECT, KEY_SELECT},
117 {XK_Print, FALSE, KEY_PRINT, KEY_SPRINT, KEY_PRINT, KEY_PRINT},
118 {XK_Find, FALSE, KEY_FIND, KEY_SFIND, KEY_FIND, KEY_FIND},
119 {XK_Pause, FALSE, KEY_SUSPEND, KEY_SSUSPEND, KEY_SUSPEND, KEY_SUSPEND},
120 {XK_Clear, FALSE, KEY_CLEAR, KEY_CLEAR, KEY_CLEAR, KEY_CLEAR},
121 {XK_Cancel, FALSE, KEY_CANCEL, KEY_SCANCEL, KEY_CANCEL, KEY_CANCEL},
122 {XK_Break, FALSE, KEY_BREAK, KEY_BREAK, KEY_BREAK, KEY_BREAK},
123 {XK_Help, FALSE, KEY_HELP, KEY_SHELP, KEY_LHELP, KEY_HELP},
124 {XK_L4, FALSE, KEY_UNDO, KEY_SUNDO, KEY_UNDO, KEY_UNDO},
125 {XK_L6, FALSE, KEY_COPY, KEY_SCOPY, KEY_COPY, KEY_COPY},
126 {XK_L9, FALSE, KEY_FIND, KEY_SFIND, KEY_FIND, KEY_FIND},
127 {XK_Menu, FALSE, KEY_OPTIONS, KEY_SOPTIONS, KEY_OPTIONS, KEY_OPTIONS},
128 #ifdef HAVE_SUNKEYSYM_H
129 {SunXK_F36, FALSE, KEY_F(41), KEY_F(43), KEY_F(45), KEY_F(47)},
130 {SunXK_F37, FALSE, KEY_F(42), KEY_F(44), KEY_F(46), KEY_F(48)},
131 #endif
132 #ifdef HAVE_DECKEYSYM_H
133 {DXK_Remove, FALSE, KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL},
134 #endif
135 {XK_Escape, FALSE, 0x1B, 0x1B, 0x1B, ALT_ESC},
136 {XK_KP_Enter, TRUE, PADENTER, PADENTER, CTL_PADENTER,ALT_PADENTER},
137 {XK_KP_Add, TRUE, PADPLUS, '+', CTL_PADPLUS, ALT_PADPLUS},
138 {XK_KP_Subtract,TRUE, PADMINUS, '-', CTL_PADMINUS,ALT_PADMINUS},
139 {XK_KP_Multiply,TRUE, PADSTAR, '*', CTL_PADSTAR, ALT_PADSTAR},
140 /* Sun Type 4 keyboard */
141 {XK_R6, TRUE, PADSTAR, '*', CTL_PADSTAR, ALT_PADSTAR},
142 {XK_KP_Divide, TRUE, PADSLASH, '/', CTL_PADSLASH,ALT_PADSLASH},
143 /* Sun Type 4 keyboard */
144 {XK_R5, TRUE, PADSLASH, '/', CTL_PADSLASH,ALT_PADSLASH},
145 {XK_KP_Decimal,TRUE, PADSTOP, '.', CTL_PADSTOP, ALT_PADSTOP},
146 {XK_KP_0, TRUE, PAD0, '0', CTL_PAD0, ALT_PAD0},
147 {XK_KP_1, TRUE, KEY_C1, '1', CTL_PAD1, ALT_PAD1},
148 {XK_KP_2, TRUE, KEY_C2, '2', CTL_PAD2, ALT_PAD2},
149 {XK_KP_3, TRUE, KEY_C3, '3', CTL_PAD3, ALT_PAD3},
150 {XK_KP_4, TRUE, KEY_B1, '4', CTL_PAD4, ALT_PAD4},
151 {XK_KP_5, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5},
152 /* Sun Type 4 keyboard */
153 {XK_R11, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5},
154 {XK_KP_6, TRUE, KEY_B3, '6', CTL_PAD6, ALT_PAD6},
155 {XK_KP_7, TRUE, KEY_A1, '7', CTL_PAD7, ALT_PAD7},
156 {XK_KP_8, TRUE, KEY_A2, '8', CTL_PAD8, ALT_PAD8},
157 {XK_KP_9, TRUE, KEY_A3, '9', CTL_PAD9, ALT_PAD9},
158 /* the following added to support Sun Type 5 keyboards */
159 {XK_F21, FALSE, KEY_SUSPEND, KEY_SSUSPEND, KEY_SUSPEND, KEY_SUSPEND},
160 {XK_F22, FALSE, KEY_PRINT, KEY_SPRINT, KEY_PRINT, KEY_PRINT},
161 {XK_F24, TRUE, PADMINUS, '-', CTL_PADMINUS,ALT_PADMINUS},
162 /* Sun Type 4 keyboard */
163 {XK_F25, TRUE, PADSLASH, '/', CTL_PADSLASH,ALT_PADSLASH},
164 /* Sun Type 4 keyboard */
165 {XK_F26, TRUE, PADSTAR, '*', CTL_PADSTAR, ALT_PADSTAR},
166 {XK_F27, TRUE, KEY_A1, '7', CTL_PAD7, ALT_PAD7},
167 {XK_F29, TRUE, KEY_A3, '9', CTL_PAD9, ALT_PAD9},
168 {XK_F31, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5},
169 {XK_F35, TRUE, KEY_C3, '3', CTL_PAD3, ALT_PAD3},
170 #ifdef HAVE_XK_KP_DELETE
171 {XK_KP_Delete, TRUE, PADSTOP, '.', CTL_PADSTOP, ALT_PADSTOP},
172 #endif
173 #ifdef HAVE_XK_KP_INSERT
174 {XK_KP_Insert, TRUE, PAD0, '0', CTL_PAD0, ALT_PAD0},
175 #endif
176 #ifdef HAVE_XK_KP_END
177 {XK_KP_End, TRUE, KEY_C1, '1', CTL_PAD1, ALT_PAD1},
178 #endif
179 #ifdef HAVE_XK_KP_DOWN
180 {XK_KP_Down, TRUE, KEY_C2, '2', CTL_PAD2, ALT_PAD2},
181 #endif
182 #ifdef HAVE_XK_KP_NEXT
183 {XK_KP_Next, TRUE, KEY_C3, '3', CTL_PAD3, ALT_PAD3},
184 #endif
185 #ifdef HAVE_XK_KP_LEFT
186 {XK_KP_Left, TRUE, KEY_B1, '4', CTL_PAD4, ALT_PAD4},
187 #endif
188 #ifdef HAVE_XK_KP_BEGIN
189 {XK_KP_Begin, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5},
190 #endif
191 #ifdef HAVE_XK_KP_RIGHT
192 {XK_KP_Right, TRUE, KEY_B3, '6', CTL_PAD6, ALT_PAD6},
193 #endif
194 #ifdef HAVE_XK_KP_HOME
195 {XK_KP_Home, TRUE, KEY_A1, '7', CTL_PAD7, ALT_PAD7},
196 #endif
197 #ifdef HAVE_XK_KP_UP
198 {XK_KP_Up, TRUE, KEY_A2, '8', CTL_PAD8, ALT_PAD8},
199 #endif
200 #ifdef HAVE_XK_KP_PRIOR
201 {XK_KP_Prior, TRUE, KEY_A3, '9', CTL_PAD9, ALT_PAD9},
202 #endif
203 {0, 0, 0, 0, 0, 0}
206 #ifndef PDC_XIM
207 # include "compose.h"
208 #endif
210 #define BITMAPDEPTH 1
212 unsigned long pdc_key_modifiers = 0L;
214 static GC normal_gc, block_cursor_gc, rect_cursor_gc, italic_gc, border_gc;
215 static int font_height, font_width, font_ascent, font_descent,
216 window_width, window_height;
217 static int resize_window_width = 0, resize_window_height = 0;
218 static char *bitmap_file = NULL;
219 #ifdef HAVE_XPM_H
220 static char *pixmap_file = NULL;
221 #endif
222 static KeySym keysym = 0;
224 static int state_mask[8] =
226 ShiftMask,
227 LockMask,
228 ControlMask,
229 Mod1Mask,
230 Mod2Mask,
231 Mod3Mask,
232 Mod4Mask,
233 Mod5Mask
236 static Atom wm_atom[2];
237 static String class_name = "XCurses";
238 static XtAppContext app_context;
239 static Widget topLevel, drawing, scrollBox, scrollVert, scrollHoriz;
240 static int received_map_notify = 0;
241 static bool mouse_selection = FALSE;
242 static chtype *tmpsel = NULL;
243 static unsigned long tmpsel_length = 0;
244 static int selection_start_x = 0, selection_start_y = 0,
245 selection_end_x = 0, selection_end_y = 0;
246 static Pixmap icon_bitmap;
247 #ifdef HAVE_XPM_H
248 static Pixmap icon_pixmap;
249 static Pixmap icon_pixmap_mask;
250 #endif
251 static bool visible_cursor = FALSE;
252 static bool window_entered = TRUE;
253 static char *program_name;
255 /* Macros just for app_resources */
257 #ifdef PDC_WIDE
258 # define DEFFONT "-misc-fixed-medium-r-normal--20-200-75-75-c-100-iso10646-1"
259 #else
260 # define DEFFONT "7x13"
261 #endif
263 #define APPDATAOFF(n) XtOffsetOf(XCursesAppData, n)
265 #define RINT(name1, name2, value) { \
266 #name1, #name2, XtRInt, \
267 sizeof(int), APPDATAOFF(name1), XtRImmediate, \
268 (XtPointer)value \
271 #define RPIXEL(name1, name2, value) { \
272 #name1, #name2, XtRPixel, \
273 sizeof(Pixel), APPDATAOFF(name1), XtRString, \
274 (XtPointer)#value \
277 #define RCOLOR(name, value) RPIXEL(color##name, Color##name, value)
279 #define RSTRINGP(name1, name2, param) { \
280 #name1, #name2, XtRString, \
281 MAX_PATH, APPDATAOFF(name1), XtRString, (XtPointer)param \
284 #define RSTRING(name1, name2) RSTRINGP(name1, name2, "")
286 #define RFONT(name1, name2, value) { \
287 #name1, #name2, XtRFontStruct, \
288 sizeof(XFontStruct), APPDATAOFF(name1), XtRString, \
289 (XtPointer)value \
292 #define RCURSOR(name1, name2, value) { \
293 #name1, #name2, XtRCursor, \
294 sizeof(Cursor), APPDATAOFF(name1), XtRString, \
295 (XtPointer)#value \
298 static XtResource app_resources[] =
300 RINT(lines, Lines, 24),
301 RINT(cols, Cols, 80),
303 RPIXEL(cursorColor, CursorColor, Red),
305 RCOLOR(Black, Black),
306 RCOLOR(Red, red3),
307 RCOLOR(Green, green3),
308 RCOLOR(Yellow, yellow3),
309 RCOLOR(Blue, blue3),
310 RCOLOR(Magenta, magenta3),
311 RCOLOR(Cyan, cyan3),
312 RCOLOR(White, Grey),
314 RCOLOR(BoldBlack, grey40),
315 RCOLOR(BoldRed, red1),
316 RCOLOR(BoldGreen, green1),
317 RCOLOR(BoldYellow, yellow1),
318 RCOLOR(BoldBlue, blue1),
319 RCOLOR(BoldMagenta, magenta1),
320 RCOLOR(BoldCyan, cyan1),
321 RCOLOR(BoldWhite, White),
323 RFONT(normalFont, NormalFont, DEFFONT),
324 RFONT(italicFont, ItalicFont, DEFFONT),
326 RSTRING(bitmap, Bitmap),
327 #ifdef HAVE_XPM_H
328 RSTRING(pixmap, Pixmap),
329 #endif
330 RSTRINGP(composeKey, ComposeKey, "Multi_key"),
332 RCURSOR(pointer, Pointer, xterm),
334 RPIXEL(pointerForeColor, PointerForeColor, Black),
335 RPIXEL(pointerBackColor, PointerBackColor, White),
337 RINT(shmmin, Shmmin, 0),
338 RINT(borderWidth, BorderWidth, 0),
340 RPIXEL(borderColor, BorderColor, Black),
342 RINT(doubleClickPeriod, DoubleClickPeriod, (PDC_CLICK_PERIOD * 2)),
343 RINT(clickPeriod, ClickPeriod, PDC_CLICK_PERIOD),
344 RINT(scrollbarWidth, ScrollbarWidth, 15),
345 RINT(cursorBlinkRate, CursorBlinkRate, 0),
347 RSTRING(textCursor, TextCursor)
350 #undef RCURSOR
351 #undef RFONT
352 #undef RSTRING
353 #undef RCOLOR
354 #undef RPIXEL
355 #undef RINT
356 #undef APPDATAOFF
357 #undef DEFFONT
359 /* Macros for options */
361 #define COPT(name) {"-" #name, "*" #name, XrmoptionSepArg, NULL}
362 #define CCOLOR(name) COPT(color##name)
364 static XrmOptionDescRec options[] =
366 COPT(lines), COPT(cols), COPT(normalFont), COPT(italicFont),
367 COPT(bitmap),
368 #ifdef HAVE_XPM_H
369 COPT(pixmap),
370 #endif
371 COPT(pointer), COPT(shmmin), COPT(composeKey), COPT(clickPeriod),
372 COPT(doubleClickPeriod), COPT(scrollbarWidth),
373 COPT(pointerForeColor), COPT(pointerBackColor),
374 COPT(cursorBlinkRate), COPT(cursorColor), COPT(textCursor),
376 CCOLOR(Black), CCOLOR(Red), CCOLOR(Green), CCOLOR(Yellow),
377 CCOLOR(Blue), CCOLOR(Magenta), CCOLOR(Cyan), CCOLOR(White),
379 CCOLOR(BoldBlack), CCOLOR(BoldRed), CCOLOR(BoldGreen),
380 CCOLOR(BoldYellow), CCOLOR(BoldBlue), CCOLOR(BoldMagenta),
381 CCOLOR(BoldCyan), CCOLOR(BoldWhite)
384 #undef CCOLOR
385 #undef COPT
387 static XtActionsRec action_table[] =
389 {"XCursesButton", (XtActionProc)XCursesButton},
390 {"XCursesKeyPress", (XtActionProc)XCursesKeyPress},
391 {"XCursesPasteSelection", (XtActionProc)XCursesPasteSelection},
392 {"string", (XtActionProc)XCursesHandleString}
395 static bool after_first_curses_request = FALSE;
396 static Pixel colors[MAX_COLORS + 2];
397 static bool vertical_cursor = FALSE;
399 #ifdef PDC_XIM
400 static XIM Xim = NULL;
401 static XIC Xic = NULL;
402 #endif
404 static const char *default_translations =
406 "<Key>: XCursesKeyPress() \n" \
407 "<KeyUp>: XCursesKeyPress() \n" \
408 "<BtnDown>: XCursesButton() \n" \
409 "<BtnUp>: XCursesButton() \n" \
410 "<BtnMotion>: XCursesButton()"
413 static int _to_utf8(char *outcode, chtype code)
415 #ifdef PDC_WIDE
416 if (code & A_ALTCHARSET && !(code & 0xff80))
417 code = acs_map[code & 0x7f];
418 #endif
419 code &= A_CHARTEXT;
421 if (code < 0x80)
423 outcode[0] = code;
424 return 1;
426 else
427 if (code < 0x800)
429 outcode[0] = ((code & 0x07c0) >> 6) | 0xc0;
430 outcode[1] = (code & 0x003f) | 0x80;
431 return 2;
433 else
435 outcode[0] = ((code & 0xf000) >> 12) | 0xe0;
436 outcode[1] = ((code & 0x0fc0) >> 6) | 0x80;
437 outcode[2] = (code & 0x003f) | 0x80;
438 return 3;
442 static int _from_utf8(wchar_t *pwc, const char *s, size_t n)
444 wchar_t key;
445 int i = -1;
446 const unsigned char *string;
448 if (!s || (n < 1))
449 return -1;
451 if (!*s)
452 return 0;
454 string = (const unsigned char *)s;
456 key = string[0];
458 /* Simplistic UTF-8 decoder -- only does the BMP, minimal validation */
460 if (key & 0x80)
462 if ((key & 0xe0) == 0xc0)
464 if (1 < n)
466 key = ((key & 0x1f) << 6) | (string[1] & 0x3f);
467 i = 2;
470 else if ((key & 0xe0) == 0xe0)
472 if (2 < n)
474 key = ((key & 0x0f) << 12) |
475 ((string[1] & 0x3f) << 6) | (string[2] & 0x3f);
476 i = 3;
480 else
481 i = 1;
483 if (i)
484 *pwc = key;
486 return i;
489 #ifndef X_HAVE_UTF8_STRING
490 static Atom XA_UTF8_STRING(Display *dpy)
492 static AtomPtr p = NULL;
494 if (!p)
495 p = XmuMakeAtom("UTF8_STRING");
497 return XmuInternAtom(dpy, p);
499 #endif
501 signal_handler XCursesSetSignal(int signo, signal_handler action)
503 #if defined(SA_INTERRUPT) || defined(SA_RESTART)
504 struct sigaction sigact, osigact;
506 sigact.sa_handler = action;
508 sigact.sa_flags =
509 # ifdef SA_INTERRUPT
510 # ifdef SA_RESTART
511 SA_INTERRUPT | SA_RESTART;
512 # else
513 SA_INTERRUPT;
514 # endif
515 # else /* must be SA_RESTART */
516 SA_RESTART;
517 # endif
518 sigemptyset(&sigact.sa_mask);
520 if (sigaction(signo, &sigact, &osigact))
521 return SIG_ERR;
523 return osigact.sa_handler;
525 #else /* not SA_INTERRUPT or SA_RESTART, use plain signal */
526 return signal(signo, action);
527 #endif
530 RETSIGTYPE XCursesSigwinchHandler(int signo)
532 PDC_LOG(("%s:XCursesSigwinchHandler() - called: SIGNO: %d\n",
533 XCLOGMSG, signo));
535 /* Patch by: Georg Fuchs, georg.fuchs@rz.uni-regensburg.de
536 02-Feb-1999 */
538 SP->resized += 1;
540 /* Always trap SIGWINCH if the C library supports SIGWINCH */
542 #ifdef SIGWINCH
543 XCursesSetSignal(SIGWINCH, XCursesSigwinchHandler);
544 #endif
547 /* Convert character positions x and y to pixel positions, stored in
548 xpos and ypos */
550 static void _make_xy(int x, int y, int *xpos, int *ypos)
552 *xpos = (x * font_width) + xc_app_data.borderWidth;
553 *ypos = xc_app_data.normalFont->ascent + (y * font_height) +
554 xc_app_data.borderWidth;
557 /* Output a block of characters with common attributes */
559 static int _new_packet(chtype attr, bool rev, int len, int col, int row,
560 #ifdef PDC_WIDE
561 XChar2b *text)
562 #else
563 char *text)
564 #endif
566 GC gc;
567 int xpos, ypos;
568 short fore, back;
570 PDC_pair_content(PAIR_NUMBER(attr), &fore, &back);
572 #ifdef PDC_WIDE
573 text[len].byte1 = text[len].byte2 = 0;
574 #else
575 text[len] = '\0';
576 #endif
578 /* Specify the color table offsets */
580 fore |= (attr & A_BOLD) ? 8 : 0;
581 back |= (attr & A_BLINK) ? 8 : 0;
583 /* Reverse flag = highlighted selection XOR A_REVERSE set */
585 rev ^= !!(attr & A_REVERSE);
587 /* Determine which GC to use - normal or italic */
589 gc = (attr & A_ITALIC) ? italic_gc : normal_gc;
591 /* Draw it */
593 XSetForeground(XCURSESDISPLAY, gc, colors[rev ? back : fore]);
594 XSetBackground(XCURSESDISPLAY, gc, colors[rev ? fore : back]);
596 _make_xy(col, row, &xpos, &ypos);
598 #ifdef PDC_WIDE
599 XDrawImageString16(
600 #else
601 XDrawImageString(
602 #endif
603 XCURSESDISPLAY, XCURSESWIN, gc, xpos, ypos, text, len);
605 /* Underline, etc. */
607 if (attr & (A_LEFTLINE|A_RIGHTLINE|A_UNDERLINE))
609 int k;
611 if (SP->line_color != -1)
612 XSetForeground(XCURSESDISPLAY, gc, colors[SP->line_color]);
614 if (attr & A_UNDERLINE) /* UNDER */
615 XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc,
616 xpos, ypos + 1, xpos + font_width * len, ypos + 1);
618 if (attr & A_LEFTLINE) /* LEFT */
619 for (k = 0; k < len; k++)
621 int x = xpos + font_width * k - 1;
622 XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc,
623 x, ypos - font_ascent, x, ypos + font_descent);
626 if (attr & A_RIGHTLINE) /* RIGHT */
627 for (k = 0; k < len; k++)
629 int x = xpos + font_width * (k + 1) - 1;
630 XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc,
631 x, ypos - font_ascent, x, ypos + font_descent);
635 PDC_LOG(("%s:_new_packet() - row: %d col: %d "
636 "num_cols: %d fore: %d back: %d text:<%s>\n",
637 XCLOGMSG, row, col, len, fore, back, text));
639 return OK;
642 /* The core display routine -- update one line of text */
644 static int _display_text(const chtype *ch, int row, int col,
645 int num_cols, bool highlight)
647 #ifdef PDC_WIDE
648 XChar2b text[513];
649 #else
650 char text[513];
651 #endif
652 chtype old_attr, attr;
653 int i, j;
655 PDC_LOG(("%s:_display_text() - called: row: %d col: %d "
656 "num_cols: %d\n", XCLOGMSG, row, col, num_cols));
658 if (!num_cols)
659 return OK;
661 old_attr = *ch & A_ATTRIBUTES;
663 for (i = 0, j = 0; j < num_cols; j++)
665 chtype curr = ch[j];
667 attr = curr & A_ATTRIBUTES;
669 #ifdef CHTYPE_LONG
670 if (attr & A_ALTCHARSET && !(curr & 0xff80))
672 attr ^= A_ALTCHARSET;
673 curr = acs_map[curr & 0x7f];
675 #endif
677 #ifndef PDC_WIDE
678 /* Special handling for ACS_BLOCK */
680 if (!(curr & A_CHARTEXT))
682 curr |= ' ';
683 attr ^= A_REVERSE;
685 #endif
686 if (attr != old_attr)
688 if (_new_packet(old_attr, highlight, i, col, row, text) == ERR)
689 return ERR;
691 old_attr = attr;
692 col += i;
693 i = 0;
696 #ifdef PDC_WIDE
697 text[i].byte1 = (curr & 0xff00) >> 8;
698 text[i++].byte2 = curr & 0x00ff;
699 #else
700 text[i++] = curr & 0xff;
701 #endif
704 return _new_packet(old_attr, highlight, i, col, row, text);
707 static void _get_gc(GC *gc, XFontStruct *font_info, int fore, int back)
709 XGCValues values;
711 /* Create default Graphics Context */
713 *gc = XCreateGC(XCURSESDISPLAY, XCURSESWIN, 0L, &values);
715 /* specify font */
717 XSetFont(XCURSESDISPLAY, *gc, font_info->fid);
719 XSetForeground(XCURSESDISPLAY, *gc, colors[fore]);
720 XSetBackground(XCURSESDISPLAY, *gc, colors[back]);
723 static void _initialize_colors(void)
725 colors[COLOR_BLACK] = xc_app_data.colorBlack;
726 colors[COLOR_RED] = xc_app_data.colorRed;
727 colors[COLOR_GREEN] = xc_app_data.colorGreen;
728 colors[COLOR_YELLOW] = xc_app_data.colorYellow;
729 colors[COLOR_BLUE] = xc_app_data.colorBlue;
730 colors[COLOR_MAGENTA] = xc_app_data.colorMagenta;
731 colors[COLOR_CYAN] = xc_app_data.colorCyan;
732 colors[COLOR_WHITE] = xc_app_data.colorWhite;
734 colors[COLOR_BLACK + 8] = xc_app_data.colorBoldBlack;
735 colors[COLOR_RED + 8] = xc_app_data.colorBoldRed;
736 colors[COLOR_GREEN + 8] = xc_app_data.colorBoldGreen;
737 colors[COLOR_YELLOW + 8] = xc_app_data.colorBoldYellow;
738 colors[COLOR_BLUE + 8] = xc_app_data.colorBoldBlue;
739 colors[COLOR_MAGENTA + 8] = xc_app_data.colorBoldMagenta;
740 colors[COLOR_CYAN + 8] = xc_app_data.colorBoldCyan;
741 colors[COLOR_WHITE + 8] = xc_app_data.colorBoldWhite;
743 colors[COLOR_CURSOR] = xc_app_data.cursorColor;
744 colors[COLOR_BORDER] = xc_app_data.borderColor;
747 static void _refresh_scrollbar(void)
749 XC_LOG(("_refresh_scrollbar() - called\n"));
751 if (SP->sb_on)
753 PDC_SCROLLBAR_TYPE total_y = SP->sb_total_y;
754 PDC_SCROLLBAR_TYPE total_x = SP->sb_total_x;
756 if (total_y)
757 XawScrollbarSetThumb(scrollVert,
758 (PDC_SCROLLBAR_TYPE)(SP->sb_cur_y) / total_y,
759 (PDC_SCROLLBAR_TYPE)(SP->sb_viewport_y) / total_y);
761 if (total_x)
762 XawScrollbarSetThumb(scrollHoriz,
763 (PDC_SCROLLBAR_TYPE)(SP->sb_cur_x) / total_x,
764 (PDC_SCROLLBAR_TYPE)(SP->sb_viewport_x) / total_x);
768 static void _set_cursor_color(chtype *ch, short *fore, short *back)
770 int attr;
771 short f, b;
773 attr = PAIR_NUMBER(*ch);
775 if (attr)
777 PDC_pair_content(attr, &f, &b);
778 *fore = 7 - (f % 8);
779 *back = 7 - (b % 8);
781 else
783 if (*ch & A_REVERSE)
785 *back = COLOR_BLACK;
786 *fore = COLOR_WHITE;
788 else
790 *back = COLOR_WHITE;
791 *fore = COLOR_BLACK;
796 static void _get_icon(void)
798 XIconSize *icon_size;
799 int size_count = 0;
800 Status rc;
801 unsigned char *bitmap_bits = NULL;
802 unsigned icon_bitmap_width = 0, icon_bitmap_height = 0,
803 file_bitmap_width = 0, file_bitmap_height = 0;
805 XC_LOG(("_get_icon() - called\n"));
807 icon_size = XAllocIconSize();
809 rc = XGetIconSizes(XtDisplay(topLevel),
810 RootWindowOfScreen(XtScreen(topLevel)),
811 &icon_size, &size_count);
813 /* if the WM can advise on icon sizes... */
815 if (rc && size_count)
817 int i, max_height = 0, max_width = 0;
819 PDC_LOG(("%s:size_count: %d rc: %d\n", XCLOGMSG, size_count, rc));
821 for (i = 0; i < size_count; i++)
823 if (icon_size[i].max_width > max_width)
824 max_width = icon_size[i].max_width;
825 if (icon_size[i].max_height > max_height)
826 max_height = icon_size[i].max_height;
828 PDC_LOG(("%s:min: %d %d\n", XCLOGMSG,
829 icon_size[i].min_width, icon_size[i].min_height));
831 PDC_LOG(("%s:max: %d %d\n", XCLOGMSG,
832 icon_size[i].max_width, icon_size[i].max_height));
834 PDC_LOG(("%s:inc: %d %d\n", XCLOGMSG,
835 icon_size[i].width_inc, icon_size[i].height_inc));
838 if (max_width >= big_icon_width && max_height >= big_icon_height)
840 icon_bitmap_width = big_icon_width;
841 icon_bitmap_height = big_icon_height;
842 bitmap_bits = (unsigned char *)big_icon_bits;
844 else
846 icon_bitmap_width = little_icon_width;
847 icon_bitmap_height = little_icon_height;
848 bitmap_bits = (unsigned char *)little_icon_bits;
852 else /* use small icon */
854 icon_bitmap_width = little_icon_width;
855 icon_bitmap_height = little_icon_height;
856 bitmap_bits = (unsigned char *)little_icon_bits;
859 XFree(icon_size);
861 #ifdef HAVE_XPM_H
862 if (xc_app_data.pixmap && xc_app_data.pixmap[0]) /* supplied pixmap */
864 XpmReadFileToPixmap(XtDisplay(topLevel),
865 RootWindowOfScreen(XtScreen(topLevel)),
866 (char *)xc_app_data.pixmap,
867 &icon_pixmap, &icon_pixmap_mask, NULL);
868 return;
870 #endif
872 if (xc_app_data.bitmap && xc_app_data.bitmap[0]) /* supplied bitmap */
874 int x_hot = 0, y_hot = 0;
876 rc = XReadBitmapFile(XtDisplay(topLevel),
877 RootWindowOfScreen(XtScreen(topLevel)),
878 (char *)xc_app_data.bitmap,
879 &file_bitmap_width, &file_bitmap_height,
880 &icon_bitmap, &x_hot, &y_hot);
882 switch(rc)
884 case BitmapOpenFailed:
885 fprintf(stderr, "bitmap file %s: not found\n",
886 xc_app_data.bitmap);
887 break;
888 case BitmapFileInvalid:
889 fprintf(stderr, "bitmap file %s: contents invalid\n",
890 xc_app_data.bitmap);
891 break;
892 default:
893 return;
897 icon_bitmap = XCreateBitmapFromData(XtDisplay(topLevel),
898 RootWindowOfScreen(XtScreen(topLevel)),
899 (char *)bitmap_bits, icon_bitmap_width, icon_bitmap_height);
902 static void _draw_border(void)
904 /* Draw the border if required */
906 if (xc_app_data.borderWidth)
907 XDrawRectangle(XCURSESDISPLAY, XCURSESWIN, border_gc,
908 xc_app_data.borderWidth / 2,
909 xc_app_data.borderWidth / 2,
910 window_width - xc_app_data.borderWidth,
911 window_height - xc_app_data.borderWidth);
914 /* Redraw the entire screen */
916 static void _display_screen(void)
918 int row;
920 XC_LOG(("_display_screen() - called\n"));
922 for (row = 0; row < XCursesLINES; row++)
924 XC_get_line_lock(row);
926 _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row)),
927 row, 0, COLS, FALSE);
929 XC_release_line_lock(row);
932 _redraw_cursor();
933 _draw_border();
936 /* Draw changed portions of the screen */
938 static void _refresh_screen(void)
940 int row, start_col, num_cols;
942 XC_LOG(("_refresh_screen() - called\n"));
944 for (row = 0; row < XCursesLINES; row++)
946 num_cols = (int)*(Xcurscr + XCURSCR_LENGTH_OFF + row);
948 if (num_cols)
950 XC_get_line_lock(row);
952 start_col = (int)*(Xcurscr + XCURSCR_START_OFF + row);
954 _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row) +
955 (start_col * sizeof(chtype))), row, start_col,
956 num_cols, FALSE);
958 *(Xcurscr + XCURSCR_LENGTH_OFF + row) = 0;
960 XC_release_line_lock(row);
964 if (mouse_selection)
965 _selection_off();
968 static void _handle_expose(Widget w, XtPointer client_data, XEvent *event,
969 Boolean *unused)
971 XC_LOG(("_handle_expose() - called\n"));
973 /* ignore all Exposes except last */
975 if (event->xexpose.count)
976 return;
978 if (after_first_curses_request && received_map_notify)
979 _display_screen();
982 static void _handle_nonmaskable(Widget w, XtPointer client_data, XEvent *event,
983 Boolean *unused)
985 XClientMessageEvent *client_event = (XClientMessageEvent *)event;
987 PDC_LOG(("%s:_handle_nonmaskable called: xc_otherpid %d event %d\n",
988 XCLOGMSG, xc_otherpid, event->type));
990 if (event->type == ClientMessage)
992 XC_LOG(("ClientMessage received\n"));
994 /* This code used to include handling of WM_SAVE_YOURSELF, but
995 it resulted in continual failure of THE on my Toshiba laptop.
996 Removed on 3-3-2001. Now only exits on WM_DELETE_WINDOW. */
998 if ((Atom)client_event->data.s[0] == wm_atom[0])
999 _exit_process(0, SIGKILL, "");
1003 static void XCursesKeyPress(Widget w, XEvent *event, String *params,
1004 Cardinal *nparams)
1006 enum { STATE_NORMAL, STATE_COMPOSE, STATE_CHAR };
1008 #ifdef PDC_XIM
1009 Status status;
1010 wchar_t buffer[120];
1011 #else
1012 unsigned char buffer[120];
1013 XComposeStatus compose;
1014 static int compose_state = STATE_NORMAL;
1015 static int compose_index = 0;
1016 int char_idx = 0;
1017 #endif
1018 unsigned long key = 0;
1019 int buflen = 40;
1020 int i, count;
1021 unsigned long modifier = 0;
1022 bool key_code = FALSE;
1024 XC_LOG(("XCursesKeyPress() - called\n"));
1026 /* Handle modifier keys first; ignore other KeyReleases */
1028 if (event->type == KeyRelease)
1030 /* The keysym value was set by a previous call to this function
1031 with a KeyPress event (or reset by the mouse event handler) */
1033 if (SP->return_key_modifiers &&
1034 #ifndef PDC_XIM
1035 keysym != compose_key &&
1036 #endif
1037 IsModifierKey(keysym))
1039 switch (keysym) {
1040 case XK_Shift_L:
1041 key = KEY_SHIFT_L;
1042 break;
1043 case XK_Shift_R:
1044 key = KEY_SHIFT_R;
1045 break;
1046 case XK_Control_L:
1047 key = KEY_CONTROL_L;
1048 break;
1049 case XK_Control_R:
1050 key = KEY_CONTROL_R;
1051 break;
1052 case XK_Alt_L:
1053 key = KEY_ALT_L;
1054 break;
1055 case XK_Alt_R:
1056 key = KEY_ALT_R;
1059 if (key)
1060 _send_key_to_curses(key, NULL, TRUE);
1063 return;
1066 buffer[0] = '\0';
1068 #ifdef PDC_XIM
1069 count = XwcLookupString(Xic, &(event->xkey), buffer, buflen,
1070 &keysym, &status);
1071 #else
1072 count = XLookupString(&(event->xkey), (char *)buffer, buflen,
1073 &keysym, &compose);
1074 #endif
1076 /* translate keysym into curses key code */
1078 PDC_LOG(("%s:Key mask: %x\n", XCLOGMSG, event->xkey.state));
1080 #ifdef PDCDEBUG
1081 for (i = 0; i < 4; i++)
1082 PDC_debug("%s:Keysym %x %d\n", XCLOGMSG,
1083 XKeycodeToKeysym(XCURSESDISPLAY, event->xkey.keycode, i), i);
1084 #endif
1086 #ifndef PDC_XIM
1088 /* Check if the key just pressed is the user-specified compose
1089 key; if it is, set the compose state and exit. */
1091 if (keysym == compose_key)
1093 chtype *ch;
1094 int xpos, ypos, save_visibility = SP->visibility;
1095 short fore = 0, back = 0;
1097 /* Change the shape of the cursor to an outline rectangle to
1098 indicate we are in "compose" status */
1100 SP->visibility = 0;
1102 _redraw_cursor();
1104 SP->visibility = save_visibility;
1105 _make_xy(SP->curscol, SP->cursrow, &xpos, &ypos);
1107 ch = (chtype *)(Xcurscr + XCURSCR_Y_OFF(SP->cursrow) +
1108 (SP->curscol * sizeof(chtype)));
1110 _set_cursor_color(ch, &fore, &back);
1112 XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]);
1114 XDrawRectangle(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc,
1115 xpos + 1, ypos - font_height +
1116 xc_app_data.normalFont->descent + 1,
1117 font_width - 2, font_height - 2);
1119 compose_state = STATE_COMPOSE;
1120 return;
1123 switch (compose_state)
1125 case STATE_COMPOSE:
1126 if (IsModifierKey(keysym))
1127 return;
1129 if (event->xkey.state & compose_mask)
1131 compose_state = STATE_NORMAL;
1132 _redraw_cursor();
1133 break;
1136 if (buffer[0] && count == 1)
1137 key = buffer[0];
1139 compose_index = -1;
1141 for (i = 0; i < (int)strlen(compose_chars); i++)
1142 if (compose_chars[i] == key)
1144 compose_index = i;
1145 break;
1148 if (compose_index == -1)
1150 compose_state = STATE_NORMAL;
1151 compose_index = 0;
1152 _redraw_cursor();
1153 break;
1156 compose_state = STATE_CHAR;
1157 return;
1159 case STATE_CHAR:
1160 if (IsModifierKey(keysym))
1161 return;
1163 if (event->xkey.state & compose_mask)
1165 compose_state = STATE_NORMAL;
1166 _redraw_cursor();
1167 break;
1170 if (buffer[0] && count == 1)
1171 key = buffer[0];
1173 char_idx = -1;
1175 for (i = 0; i < MAX_COMPOSE_CHARS; i++)
1176 if (compose_lookups[compose_index][i] == key)
1178 char_idx = i;
1179 break;
1182 if (char_idx == -1)
1184 compose_state = STATE_NORMAL;
1185 compose_index = 0;
1186 _redraw_cursor();
1187 break;
1190 _send_key_to_curses(compose_keys[compose_index][char_idx],
1191 NULL, FALSE);
1193 compose_state = STATE_NORMAL;
1194 compose_index = 0;
1196 _redraw_cursor();
1198 return;
1201 #endif /* PDC_XIM */
1203 /* To get here we are procesing "normal" keys */
1205 PDC_LOG(("%s:Keysym %x %d\n", XCLOGMSG,
1206 XKeycodeToKeysym(XCURSESDISPLAY, event->xkey.keycode, key), key));
1208 if (SP->save_key_modifiers)
1210 /* 0x10: usually, numlock modifier */
1212 if (event->xkey.state & Mod2Mask)
1213 modifier |= PDC_KEY_MODIFIER_NUMLOCK;
1215 /* 0x01: shift modifier */
1217 if (event->xkey.state & ShiftMask)
1218 modifier |= PDC_KEY_MODIFIER_SHIFT;
1220 /* 0x04: control modifier */
1222 if (event->xkey.state & ControlMask)
1223 modifier |= PDC_KEY_MODIFIER_CONTROL;
1225 /* 0x08: usually, alt modifier */
1227 if (event->xkey.state & Mod1Mask)
1228 modifier |= PDC_KEY_MODIFIER_ALT;
1231 for (i = 0; key_table[i].keycode; i++)
1233 if (key_table[i].keycode == keysym)
1235 PDC_LOG(("%s:State %x\n", XCLOGMSG, event->xkey.state));
1237 /* ControlMask: 0x04: control modifier
1238 Mod1Mask: 0x08: usually, alt modifier
1239 Mod2Mask: 0x10: usually, numlock modifier
1240 ShiftMask: 0x01: shift modifier */
1242 if ((event->xkey.state & ShiftMask) ||
1243 (key_table[i].numkeypad &&
1244 (event->xkey.state & Mod2Mask)))
1246 key = key_table[i].shifted;
1248 else if (event->xkey.state & ControlMask)
1250 key = key_table[i].control;
1252 else if (event->xkey.state & Mod1Mask)
1254 key = key_table[i].alt;
1257 /* To get here, we ignore all other modifiers */
1259 else
1260 key = key_table[i].normal;
1262 key_code = (key > 0x100);
1263 break;
1267 if (!key && buffer[0] && count == 1)
1268 key = buffer[0];
1270 PDC_LOG(("%s:Key: %s pressed - %x Mod: %x\n", XCLOGMSG,
1271 XKeysymToString(keysym), key, event->xkey.state));
1273 /* Handle ALT letters and numbers */
1275 if (event->xkey.state == Mod1Mask)
1277 if (key >= 'A' && key <= 'Z')
1279 key += ALT_A - 'A';
1280 key_code = TRUE;
1283 if (key >= 'a' && key <= 'z')
1285 key += ALT_A - 'a';
1286 key_code = TRUE;
1289 if (key >= '0' && key <= '9')
1291 key += ALT_0 - '0';
1292 key_code = TRUE;
1296 /* After all that, send the key back to the application if is
1297 NOT zero. */
1299 if (key)
1301 key |= (modifier << 24);
1303 _send_key_to_curses(key, NULL, key_code);
1307 static void XCursesHandleString(Widget w, XEvent *event, String *params,
1308 Cardinal *nparams)
1310 unsigned char *ptr;
1312 if (*nparams != 1)
1313 return;
1315 ptr = (unsigned char *)*params;
1317 if (ptr[0] == '0' && ptr[1] == 'x' && ptr[2] != '\0')
1319 unsigned char c;
1320 unsigned long total = 0;
1322 for (ptr += 2; (c = tolower(*ptr)); ptr++)
1324 total <<= 4;
1326 if (c >= '0' && c <= '9')
1327 total += c - '0';
1328 else
1329 if (c >= 'a' && c <= 'f')
1330 total += c - ('a' - 10);
1331 else
1332 break;
1335 if (c == '\0')
1336 _send_key_to_curses(total, NULL, FALSE);
1338 else
1339 for (; *ptr; ptr++)
1340 _send_key_to_curses((unsigned long)*ptr, NULL, FALSE);
1343 static void _paste_string(Widget w, XtPointer data, Atom *selection, Atom *type,
1344 XtPointer value, unsigned long *length, int *format)
1346 unsigned long i, key;
1347 unsigned char *string = value;
1349 XC_LOG(("_paste_string() - called\n"));
1351 if (!*type || !*length || !string)
1352 return;
1354 for (i = 0; string[i] && (i < (*length)); i++)
1356 key = string[i];
1358 if (key == 10) /* new line - convert to ^M */
1359 key = 13;
1361 _send_key_to_curses(key, NULL, FALSE);
1364 XtFree(value);
1367 static void _paste_utf8(Widget w, XtPointer event, Atom *selection, Atom *type,
1368 XtPointer value, unsigned long *length, int *format)
1370 wchar_t key;
1371 size_t i = 0, len;
1372 char *string = value;
1374 XC_LOG(("_paste_utf8() - called\n"));
1376 if (!*type || !*length)
1378 XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _paste_string,
1379 event, ((XButtonEvent *)event)->time);
1380 return;
1383 len = *length;
1385 if (!string)
1386 return;
1388 while (string[i] && (i < len))
1390 int retval = _from_utf8(&key, string + i, len - i);
1392 if (retval < 1)
1393 return;
1395 if (key == 10) /* new line - convert to ^M */
1396 key = 13;
1398 _send_key_to_curses(key, NULL, FALSE);
1400 i += retval;
1403 XtFree(value);
1406 static void XCursesPasteSelection(Widget w, XButtonEvent *button_event)
1408 XC_LOG(("XCursesPasteSelection() - called\n"));
1410 XtGetSelectionValue(w, XA_PRIMARY, XA_UTF8_STRING(XtDisplay(w)),
1411 _paste_utf8, (XtPointer)button_event,
1412 button_event->time);
1415 static Boolean _convert_proc(Widget w, Atom *selection, Atom *target,
1416 Atom *type_return, XtPointer *value_return,
1417 unsigned long *length_return, int *format_return)
1419 XC_LOG(("_convert_proc() - called\n"));
1421 if (*target == XA_TARGETS(XtDisplay(topLevel)))
1423 XSelectionRequestEvent *req = XtGetSelectionRequest(w,
1424 *selection, (XtRequestId)NULL);
1426 Atom *targetP;
1427 XPointer std_targets;
1428 unsigned long std_length;
1430 XmuConvertStandardSelection(topLevel, req->time, selection,
1431 target, type_return, &std_targets,
1432 &std_length, format_return);
1434 *length_return = std_length + 2;
1435 *value_return = XtMalloc(sizeof(Atom) * (*length_return));
1437 targetP = *(Atom**)value_return;
1438 *targetP++ = XA_STRING;
1439 *targetP++ = XA_UTF8_STRING(XtDisplay(topLevel));
1441 memmove((void *)targetP, (const void *)std_targets,
1442 sizeof(Atom) * std_length);
1444 XtFree((char *)std_targets);
1445 *type_return = XA_ATOM;
1446 *format_return = sizeof(Atom) * 8;
1448 return True;
1450 else if (*target == XA_UTF8_STRING(XtDisplay(topLevel)) ||
1451 *target == XA_STRING)
1453 bool utf8 = !(*target == XA_STRING);
1454 char *data = XtMalloc(tmpsel_length * 3 + 1);
1455 chtype *tmp = tmpsel;
1456 int ret_length = 0;
1458 if (utf8)
1460 while (*tmp)
1461 ret_length += _to_utf8(data + ret_length, *tmp++);
1463 else
1464 while (*tmp)
1465 data[ret_length++] = *tmp++ & 0xff;
1467 data[ret_length++] = '\0';
1469 *value_return = data;
1470 *length_return = ret_length;
1471 *format_return = 8;
1472 *type_return = *target;
1474 return True;
1476 else
1477 return XmuConvertStandardSelection(topLevel, CurrentTime,
1478 selection, target, type_return, (XPointer*)value_return,
1479 length_return, format_return);
1482 static void _lose_ownership(Widget w, Atom *type)
1484 XC_LOG(("_lose_ownership() - called\n"));
1486 if (tmpsel)
1487 free(tmpsel);
1489 tmpsel = NULL;
1490 tmpsel_length = 0;
1491 _selection_off();
1494 static void _show_selection(int start_x, int start_y, int end_x, int end_y,
1495 bool highlight)
1497 int i, num_cols, start_col, row;
1499 PDC_LOG(("%s:_show_selection() - called StartX: %d StartY: %d "
1500 "EndX: %d EndY: %d Highlight: %d\n", XCLOGMSG,
1501 start_x, start_y, end_x, end_y, highlight));
1503 for (i = 0; i < end_y - start_y + 1; i++)
1505 if (start_y == end_y) /* only one line */
1507 start_col = start_x;
1508 num_cols = end_x - start_x + 1;
1509 row = start_y;
1511 else if (!i) /* first line */
1513 start_col = start_x;
1514 num_cols = COLS - start_x;
1515 row = start_y;
1517 else if (start_y + i == end_y) /* last line */
1519 start_col = 0;
1520 num_cols = end_x + 1;
1521 row = end_y;
1523 else /* full line */
1525 start_col = 0;
1526 num_cols = COLS;
1527 row = start_y + i;
1530 XC_get_line_lock(row);
1532 _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row) +
1533 (start_col * sizeof(chtype))), row, start_col,
1534 num_cols, highlight);
1536 XC_release_line_lock(row);
1540 static void _selection_off(void)
1542 XC_LOG(("_selection_off() - called\n"));
1544 _display_screen();
1546 selection_start_x = selection_start_y = selection_end_x =
1547 selection_end_y = 0;
1549 mouse_selection = FALSE;
1552 static void _selection_on(int x, int y)
1554 XC_LOG(("_selection_on() - called\n"));
1556 selection_start_x = selection_end_x = x;
1557 selection_start_y = selection_end_y = y;
1560 static void _selection_extend(int x, int y)
1562 int temp, current_start, current_end, current_start_x,
1563 current_end_x, current_start_y, current_end_y, new_start,
1564 new_end, new_start_x, new_end_x, new_start_y, new_end_y;
1566 XC_LOG(("_selection_extend() - called\n"));
1568 mouse_selection = TRUE;
1570 /* convert x/y coordinates into start/stop */
1572 current_start = (selection_start_y * COLS) + selection_start_x;
1573 current_end = (selection_end_y * COLS) + selection_end_x;
1575 if (current_start > current_end)
1577 current_start_x = selection_end_x;
1578 current_start_y = selection_end_y;
1579 current_end_x = selection_start_x;
1580 current_end_y = selection_start_y;
1581 temp = current_start;
1582 current_start = current_end;
1583 current_end = temp;
1585 else
1587 current_end_x = selection_end_x;
1588 current_end_y = selection_end_y;
1589 current_start_x = selection_start_x;
1590 current_start_y = selection_start_y;
1593 /* Now we have the current selection as a linear expression.
1594 Convert the new position to a linear expression. */
1596 selection_end_x = x;
1597 selection_end_y = y;
1599 /* convert x/y coordinates into start/stop */
1601 new_start = (selection_start_y * COLS) + selection_start_x;
1602 new_end = (selection_end_y * COLS) + selection_end_x;
1604 if (new_start > new_end)
1606 new_start_x = selection_end_x;
1607 new_start_y = selection_end_y;
1608 new_end_x = selection_start_x;
1609 new_end_y = selection_start_y;
1610 temp = new_start;
1611 new_start = new_end;
1612 new_end = temp;
1614 else
1616 new_end_x = selection_end_x;
1617 new_end_y = selection_end_y;
1618 new_start_x = selection_start_x;
1619 new_start_y = selection_start_y;
1622 if (new_end > current_end)
1623 _show_selection(current_end_x, current_end_y, new_end_x,
1624 new_end_y, TRUE);
1625 else if (new_end < current_end)
1626 _show_selection(new_end_x, new_end_y, current_end_x,
1627 current_end_y, FALSE);
1628 else if (new_start < current_start)
1629 _show_selection(new_start_x, new_start_y, current_start_x,
1630 current_start_y, TRUE);
1631 else if (new_start > current_start)
1632 _show_selection(current_start_x, current_start_y,
1633 new_start_x, new_start_y, FALSE);
1634 else
1635 _show_selection(current_start_x, current_start_y,
1636 new_start_x, new_start_y, TRUE);
1639 static void _selection_set(void)
1641 int i, j, start, end, start_x, end_x, start_y, end_y, num_cols,
1642 start_col, row, num_chars, ch, last_nonblank, length, newlen;
1643 chtype *ptr = NULL;
1645 XC_LOG(("_selection_set() - called\n"));
1647 /* convert x/y coordinates into start/stop */
1649 start = (selection_start_y * COLS) + selection_start_x;
1650 end = (selection_end_y * COLS) + selection_end_x;
1652 if (start == end)
1654 if (tmpsel)
1655 free(tmpsel);
1657 tmpsel = NULL;
1658 tmpsel_length = 0;
1660 return;
1663 if (start > end)
1665 start_x = selection_end_x;
1666 start_y = selection_end_y;
1667 end_x = selection_start_x;
1668 end_y = selection_start_y;
1669 length = start - end + 1;
1671 else
1673 end_x = selection_end_x;
1674 end_y = selection_end_y;
1675 start_x = selection_start_x;
1676 start_y = selection_start_y;
1677 length = end - start + 1;
1680 newlen = length + end_y - start_y + 2;
1682 if (length > (int)tmpsel_length)
1684 if (!tmpsel_length)
1685 tmpsel = malloc(newlen * sizeof(chtype));
1686 else
1687 tmpsel = realloc(tmpsel, newlen * sizeof(chtype));
1690 if (!tmpsel)
1692 tmpsel_length = 0;
1693 return;
1696 tmpsel_length = length;
1697 num_chars = 0;
1699 for (i = 0; i < end_y - start_y + 1; i++)
1702 if (start_y == end_y) /* only one line */
1704 start_col = start_x;
1705 num_cols = end_x - start_x + 1;
1706 row = start_y;
1708 else if (!i) /* first line */
1710 start_col = start_x;
1711 num_cols = COLS - start_x;
1712 row = start_y;
1714 else if (start_y + i == end_y) /* last line */
1716 start_col = 0;
1717 num_cols = end_x + 1;
1718 row = end_y;
1720 else /* full line */
1722 start_col = 0;
1723 num_cols = COLS;
1724 row = start_y + i;
1727 XC_get_line_lock(row);
1729 ptr = (chtype *)(Xcurscr + XCURSCR_Y_OFF(row) +
1730 start_col * sizeof(chtype));
1732 if (i < end_y - start_y)
1734 last_nonblank = 0;
1736 for (j = 0; j < num_cols; j++)
1738 ch = (int)(ptr[j] & A_CHARTEXT);
1739 if (ch != (int)' ')
1740 last_nonblank = j;
1743 else
1744 last_nonblank = num_cols - 1;
1746 for (j = 0; j <= last_nonblank; j++)
1747 tmpsel[num_chars++] = ptr[j];
1749 XC_release_line_lock(row);
1751 if (i < end_y - start_y)
1752 tmpsel[num_chars++] = '\n';
1755 tmpsel[num_chars] = '\0';
1756 tmpsel_length = num_chars;
1759 static void _display_cursor(int old_row, int old_x, int new_row, int new_x)
1761 int xpos, ypos, i;
1762 chtype *ch;
1763 short fore = 0, back = 0;
1765 PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n",
1766 XCLOGMSG, old_row, old_x));
1768 /* if the cursor position is outside the boundary of the screen,
1769 ignore the request */
1771 if (old_row >= XCursesLINES || old_x >= COLS ||
1772 new_row >= XCursesLINES || new_x >= COLS)
1773 return;
1775 /* display the character at the current cursor position */
1777 PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n",
1778 XCLOGMSG, old_row, old_x));
1780 _display_text((const chtype *)(Xcurscr + (XCURSCR_Y_OFF(old_row) +
1781 (old_x * sizeof(chtype)))), old_row, old_x, 1, FALSE);
1783 /* display the cursor at the new cursor position */
1785 if (!SP->visibility)
1786 return; /* cursor not displayed, no more to do */
1788 _make_xy(new_x, new_row, &xpos, &ypos);
1790 ch = (chtype *)(Xcurscr + XCURSCR_Y_OFF(new_row) + new_x * sizeof(chtype));
1792 _set_cursor_color(ch, &fore, &back);
1794 if (vertical_cursor)
1796 XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]);
1798 for (i = 1; i <= SP->visibility; i++)
1799 XDrawLine(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc,
1800 xpos + i, ypos - xc_app_data.normalFont->ascent,
1801 xpos + i, ypos - xc_app_data.normalFont->ascent +
1802 font_height - 1);
1804 else
1806 if (SP->visibility == 1)
1808 /* cursor visibility normal */
1810 XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]);
1812 for (i = 0; i < xc_app_data.normalFont->descent + 2; i++)
1813 XDrawLine(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc,
1814 xpos, ypos - 2 + i, xpos + font_width, ypos - 2 + i);
1816 else
1818 /* cursor visibility high */
1819 #ifdef PDC_WIDE
1820 XChar2b buf[2];
1822 buf[0].byte1 = (*ch & 0xff00) >> 8;
1823 buf[0].byte2 = *ch & 0x00ff;
1825 buf[1].byte1 = buf[1].byte2 = 0;
1826 #else
1827 char buf[2];
1829 buf[0] = *ch & 0xff;
1830 buf[1] = '\0';
1831 #endif
1832 XSetForeground(XCURSESDISPLAY, block_cursor_gc, colors[fore]);
1833 XSetBackground(XCURSESDISPLAY, block_cursor_gc, colors[back]);
1834 #ifdef PDC_WIDE
1835 XDrawImageString16(
1836 #else
1837 XDrawImageString(
1838 #endif
1839 XCURSESDISPLAY, XCURSESWIN, block_cursor_gc,
1840 xpos, ypos, buf, 1);
1844 PDC_LOG(("%s:_display_cursor() - draw cursor at row %d col %d\n",
1845 XCLOGMSG, new_row, new_x));
1848 static void _redraw_cursor(void)
1850 _display_cursor(SP->cursrow, SP->curscol, SP->cursrow, SP->curscol);
1853 static void _handle_enter_leave(Widget w, XtPointer client_data,
1854 XEvent *event, Boolean *unused)
1856 XC_LOG(("_handle_enter_leave called\n"));
1858 switch(event->type)
1860 case EnterNotify:
1861 XC_LOG(("EnterNotify received\n"));
1863 window_entered = TRUE;
1864 break;
1866 case LeaveNotify:
1867 XC_LOG(("LeaveNotify received\n"));
1869 window_entered = FALSE;
1871 /* Display the cursor so it stays on while the window is
1872 not current */
1874 _redraw_cursor();
1875 break;
1877 default:
1878 PDC_LOG(("%s:_handle_enter_leave - unknown event %d\n",
1879 XCLOGMSG, event->type));
1883 static void _send_key_to_curses(unsigned long key, MOUSE_STATUS *ms,
1884 bool key_code)
1886 PDC_LOG(("%s:_send_key_to_curses() - called: sending %d\n",
1887 XCLOGMSG, key));
1889 SP->key_code = key_code;
1891 if (XC_write_socket(xc_key_sock, &key, sizeof(unsigned long)) < 0)
1892 _exit_process(1, SIGKILL, "exiting from _send_key_to_curses");
1894 if (ms)
1896 MOUSE_LOG(("%s:writing mouse stuff\n", XCLOGMSG));
1898 if (XC_write_socket(xc_key_sock, ms, sizeof(MOUSE_STATUS)) < 0)
1899 _exit_process(1, SIGKILL, "exiting from _send_key_to_curses");
1903 static void _blink_cursor(XtPointer unused, XtIntervalId *id)
1905 XC_LOG(("_blink_cursor() - called:\n"));
1907 if (window_entered)
1909 if (visible_cursor)
1911 /* Cursor currently ON, turn it off */
1913 int save_visibility = SP->visibility;
1914 SP->visibility = 0;
1915 _redraw_cursor();
1916 SP->visibility = save_visibility;
1917 visible_cursor = FALSE;
1919 else
1921 /* Cursor currently OFF, turn it on */
1923 _redraw_cursor();
1924 visible_cursor = TRUE;
1928 XtAppAddTimeOut(app_context, xc_app_data.cursorBlinkRate,
1929 _blink_cursor, NULL);
1932 static void XCursesButton(Widget w, XEvent *event, String *params,
1933 Cardinal *nparams)
1935 int button_no;
1936 static int last_button_no = 0;
1937 static Time last_button_press_time = 0;
1938 MOUSE_STATUS save_mouse_status;
1939 bool send_key = TRUE;
1940 static bool remove_release;
1941 static bool handle_real_release;
1943 XC_LOG(("XCursesButton() - called\n"));
1945 keysym = 0; /* suppress any modifier key return */
1947 save_mouse_status = Mouse_status;
1948 button_no = event->xbutton.button;
1950 /* It appears that under X11R6 (at least on Linux), that an
1951 event_type of ButtonMotion does not include the mouse button in
1952 the event. The following code is designed to cater for this
1953 situation. */
1955 if (!button_no)
1956 button_no = last_button_no;
1958 last_button_no = button_no;
1960 Mouse_status.changes = 0;
1962 switch(event->type)
1964 case ButtonPress:
1965 /* Handle button 4 and 5, which are normally mapped to the wheel
1966 mouse scroll up and down */
1968 if (button_no == 4 || button_no == 5)
1970 /* Send the KEY_MOUSE to curses program */
1972 memset(&Mouse_status, 0, sizeof(Mouse_status));
1974 Mouse_status.changes = (button_no == 5) ?
1975 PDC_MOUSE_WHEEL_DOWN : PDC_MOUSE_WHEEL_UP;
1977 MOUSE_X_POS = MOUSE_Y_POS = -1;
1978 _send_key_to_curses(KEY_MOUSE, &Mouse_status, TRUE);
1979 remove_release = TRUE;
1981 return;
1984 if (button_no == 2 &&
1985 (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
1987 XCursesPasteSelection(drawing, (XButtonEvent *)event);
1988 remove_release = TRUE;
1990 return;
1993 remove_release = False;
1994 handle_real_release = False;
1996 MOUSE_LOG(("\nButtonPress\n"));
1998 if ((event->xbutton.time - last_button_press_time) <
1999 xc_app_data.doubleClickPeriod)
2001 MOUSE_X_POS = save_mouse_status.x;
2002 MOUSE_Y_POS = save_mouse_status.y;
2003 BUTTON_STATUS(button_no) = BUTTON_DOUBLE_CLICKED;
2005 _selection_off();
2006 remove_release = True;
2008 else
2010 napms(SP->mouse_wait);
2011 event->type = ButtonRelease;
2012 XSendEvent(event->xbutton.display, event->xbutton.window,
2013 True, 0, event);
2014 last_button_press_time = event->xbutton.time;
2016 return;
2019 last_button_press_time = event->xbutton.time;
2020 break;
2022 case MotionNotify:
2023 MOUSE_LOG(("\nMotionNotify: y: %d x: %d Width: %d "
2024 "Height: %d\n", event->xbutton.y, event->xbutton.x,
2025 font_width, font_height));
2027 MOUSE_X_POS = (event->xbutton.x - xc_app_data.borderWidth) /
2028 font_width;
2029 MOUSE_Y_POS = (event->xbutton.y - xc_app_data.borderWidth) /
2030 font_height;
2032 if (button_no == 1 &&
2033 (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2035 _selection_extend(MOUSE_X_POS, MOUSE_Y_POS);
2036 send_key = FALSE;
2038 else
2039 _selection_off();
2041 /* Throw away mouse movements if they are in the same character
2042 position as the last mouse event, or if we are currently in
2043 the middle of a double click event. */
2045 if ((MOUSE_X_POS == save_mouse_status.x &&
2046 MOUSE_Y_POS == save_mouse_status.y) ||
2047 save_mouse_status.button[button_no - 1] == BUTTON_DOUBLE_CLICKED)
2049 send_key = FALSE;
2050 break;
2053 Mouse_status.changes |= PDC_MOUSE_MOVED;
2054 break;
2056 case ButtonRelease:
2057 if (remove_release)
2059 MOUSE_LOG(("Release at: %ld - removed\n", event->xbutton.time));
2060 return;
2062 else
2064 MOUSE_X_POS = (event->xbutton.x - xc_app_data.borderWidth) /
2065 font_width;
2066 MOUSE_Y_POS = (event->xbutton.y - xc_app_data.borderWidth) /
2067 font_height;
2069 if (!handle_real_release)
2071 if ((event->xbutton.time - last_button_press_time) <
2072 SP->mouse_wait &&
2073 (event->xbutton.time != last_button_press_time))
2075 /* The "real" release was shorter than usleep() time;
2076 therefore generate a click event */
2078 MOUSE_LOG(("Release at: %ld - click\n",
2079 event->xbutton.time));
2081 BUTTON_STATUS(button_no) = BUTTON_CLICKED;
2083 if (button_no == 1 && mouse_selection &&
2084 (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2086 send_key = FALSE;
2088 if (XtOwnSelection(topLevel, XA_PRIMARY,
2089 event->xbutton.time, _convert_proc,
2090 _lose_ownership, NULL) == False)
2091 _selection_off();
2093 else
2094 _selection_off();
2096 /* Ensure the "pseudo" release event is ignored */
2098 remove_release = True;
2099 handle_real_release = False;
2100 break;
2102 else
2104 /* Button release longer than usleep() time;
2105 therefore generate a press and wait for the real
2106 release to occur later. */
2108 MOUSE_LOG(("Generated Release at: %ld - "
2109 "press & release\n", event->xbutton.time));
2111 BUTTON_STATUS(button_no) = BUTTON_PRESSED;
2113 if (button_no == 1 &&
2114 (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2116 _selection_off();
2117 _selection_on(MOUSE_X_POS, MOUSE_Y_POS);
2120 handle_real_release = True;
2121 break;
2124 else
2126 MOUSE_LOG(("Release at: %ld - released\n",
2127 event->xbutton.time));
2131 MOUSE_LOG(("\nButtonRelease\n"));
2133 BUTTON_STATUS(button_no) = BUTTON_RELEASED;
2135 if (button_no == 1 && mouse_selection &&
2136 (!SP->_trap_mbe || (event->xbutton.state & ShiftMask)))
2138 send_key = FALSE;
2140 if (XtOwnSelection(topLevel, XA_PRIMARY,
2141 event->xbutton.time, _convert_proc,
2142 _lose_ownership, NULL) == False)
2143 _selection_off();
2145 _selection_set();
2147 else
2148 _selection_off();
2150 break;
2153 /* Set up the mouse status fields in preparation for sending */
2155 Mouse_status.changes |= 1 << (button_no - 1);
2157 if (Mouse_status.changes & PDC_MOUSE_MOVED &&
2158 BUTTON_STATUS(button_no) == BUTTON_PRESSED)
2159 BUTTON_STATUS(button_no) = BUTTON_MOVED;
2161 if (event->xbutton.state & ShiftMask)
2162 BUTTON_STATUS(button_no) |= BUTTON_SHIFT;
2163 if (event->xbutton.state & ControlMask)
2164 BUTTON_STATUS(button_no) |= BUTTON_CONTROL;
2165 if (event->xbutton.state & Mod1Mask)
2166 BUTTON_STATUS(button_no) |= BUTTON_ALT;
2168 /* If we are ignoring the event, or the mouse position is outside
2169 the bounds of the screen (because of the border), return here */
2171 MOUSE_LOG(("Button: %d x: %d y: %d Button status: %x "
2172 "Mouse status: %x\n", button_no, MOUSE_X_POS, MOUSE_Y_POS,
2173 BUTTON_STATUS(button_no), Mouse_status.changes));
2175 MOUSE_LOG(("Send: %d Button1: %x Button2: %x Button3: %x %d %d\n",
2176 send_key, BUTTON_STATUS(1), BUTTON_STATUS(2),
2177 BUTTON_STATUS(3), XCursesLINES, XCursesCOLS));
2179 if (!send_key || MOUSE_X_POS < 0 || MOUSE_X_POS >= XCursesCOLS ||
2180 MOUSE_Y_POS < 0 || MOUSE_Y_POS >= XCursesLINES)
2181 return;
2183 /* Send the KEY_MOUSE to curses program */
2185 _send_key_to_curses(KEY_MOUSE, &Mouse_status, TRUE);
2188 static void _scroll_up_down(Widget w, XtPointer client_data,
2189 XtPointer call_data)
2191 int pixels = (long) call_data;
2192 int total_y = SP->sb_total_y * font_height;
2193 int viewport_y = SP->sb_viewport_y * font_height;
2194 int cur_y = SP->sb_cur_y * font_height;
2196 /* When pixels is negative, right button pressed, move data down,
2197 thumb moves up. Otherwise, left button pressed, pixels positive,
2198 move data up, thumb down. */
2200 cur_y += pixels;
2202 /* limit panning to size of overall */
2204 if (cur_y < 0)
2205 cur_y = 0;
2206 else
2207 if (cur_y > (total_y - viewport_y))
2208 cur_y = total_y - viewport_y;
2210 SP->sb_cur_y = cur_y / font_height;
2212 XawScrollbarSetThumb(w, (double)((double)cur_y / (double)total_y),
2213 (double)((double)viewport_y / (double)total_y));
2215 /* Send a key: if pixels negative, send KEY_SCROLL_DOWN */
2217 _send_key_to_curses(KEY_SF, NULL, TRUE);
2220 static void _scroll_left_right(Widget w, XtPointer client_data,
2221 XtPointer call_data)
2223 int pixels = (long) call_data;
2224 int total_x = SP->sb_total_x * font_width;
2225 int viewport_x = SP->sb_viewport_x * font_width;
2226 int cur_x = SP->sb_cur_x * font_width;
2228 cur_x += pixels;
2230 /* limit panning to size of overall */
2232 if (cur_x < 0)
2233 cur_x = 0;
2234 else
2235 if (cur_x > (total_x - viewport_x))
2236 cur_x = total_x - viewport_x;
2238 SP->sb_cur_x = cur_x / font_width;
2240 XawScrollbarSetThumb(w, (double)((double)cur_x / (double)total_x),
2241 (double)((double)viewport_x / (double)total_x));
2243 _send_key_to_curses(KEY_SR, NULL, TRUE);
2246 static void _thumb_up_down(Widget w, XtPointer client_data,
2247 XtPointer call_data)
2249 double percent = *(double *) call_data;
2250 double total_y = (double)SP->sb_total_y;
2251 double viewport_y = (double)SP->sb_viewport_y;
2252 int cur_y = SP->sb_cur_y;
2254 /* If the size of the viewport is > overall area simply return,
2255 as no scrolling is permitted. */
2257 if (SP->sb_viewport_y >= SP->sb_total_y)
2258 return;
2260 if ((SP->sb_cur_y = (int)((double)total_y * percent)) >=
2261 (total_y - viewport_y))
2262 SP->sb_cur_y = total_y - viewport_y;
2264 XawScrollbarSetThumb(w, (double)(cur_y / total_y),
2265 (double)(viewport_y / total_y));
2267 _send_key_to_curses(KEY_SF, NULL, TRUE);
2270 static void _thumb_left_right(Widget w, XtPointer client_data,
2271 XtPointer call_data)
2273 double percent = *(double *) call_data;
2274 double total_x = (double)SP->sb_total_x;
2275 double viewport_x = (double)SP->sb_viewport_x;
2276 int cur_x = SP->sb_cur_x;
2278 if (SP->sb_viewport_x >= SP->sb_total_x)
2279 return;
2281 if ((SP->sb_cur_x = (int)((float)total_x * percent)) >=
2282 (total_x - viewport_x))
2283 SP->sb_cur_x = total_x - viewport_x;
2285 XawScrollbarSetThumb(w, (double)(cur_x / total_x),
2286 (double)(viewport_x / total_x));
2288 _send_key_to_curses(KEY_SR, NULL, TRUE);
2291 static void _exit_process(int rc, int sig, char *msg)
2293 if (rc || sig)
2294 fprintf(stderr, "%s:_exit_process() - called: rc:%d sig:%d <%s>\n",
2295 XCLOGMSG, rc, sig, msg);
2297 shmdt((char *)SP);
2298 shmdt((char *)Xcurscr);
2299 shmctl(shmidSP, IPC_RMID, 0);
2300 shmctl(shmid_Xcurscr, IPC_RMID, 0);
2302 if (bitmap_file)
2304 XFreePixmap(XCURSESDISPLAY, icon_bitmap);
2305 free(bitmap_file);
2308 #ifdef HAVE_XPM_H
2309 if (pixmap_file)
2311 XFreePixmap(XCURSESDISPLAY, icon_pixmap);
2312 XFreePixmap(XCURSESDISPLAY, icon_pixmap_mask);
2313 free(pixmap_file);
2315 #endif
2316 XFreeGC(XCURSESDISPLAY, normal_gc);
2317 XFreeGC(XCURSESDISPLAY, italic_gc);
2318 XFreeGC(XCURSESDISPLAY, block_cursor_gc);
2319 XFreeGC(XCURSESDISPLAY, rect_cursor_gc);
2320 XFreeGC(XCURSESDISPLAY, border_gc);
2321 #ifdef PDC_XIM
2322 XDestroyIC(Xic);
2323 #endif
2325 shutdown(xc_display_sock, 2);
2326 close(xc_display_sock);
2328 shutdown(xc_exit_sock, 2);
2329 close(xc_exit_sock);
2331 shutdown(xc_key_sock, 2);
2332 close(xc_key_sock);
2334 if (sig)
2335 kill(xc_otherpid, sig); /* to kill parent process */
2337 _exit(rc);
2340 static void _resize(void)
2342 short save_atrtab[PDC_COLOR_PAIRS * 2];
2344 after_first_curses_request = FALSE;
2346 SP->lines = XCursesLINES = ((resize_window_height -
2347 (2 * xc_app_data.borderWidth)) / font_height);
2349 LINES = XCursesLINES - SP->linesrippedoff - SP->slklines;
2351 SP->cols = COLS = XCursesCOLS = ((resize_window_width -
2352 (2 * xc_app_data.borderWidth)) / font_width);
2354 window_width = resize_window_width;
2355 window_height = resize_window_height;
2356 visible_cursor = TRUE;
2358 _draw_border();
2360 /* Detach and drop the current shared memory segment and create and
2361 attach to a new segment */
2363 memcpy(save_atrtab, xc_atrtab, sizeof(save_atrtab));
2365 SP->XcurscrSize = XCURSCR_SIZE;
2366 shmdt((char *)Xcurscr);
2367 shmctl(shmid_Xcurscr, IPC_RMID, 0);
2369 if ((shmid_Xcurscr = shmget(shmkey_Xcurscr,
2370 SP->XcurscrSize + XCURSESSHMMIN, 0700 | IPC_CREAT)) < 0)
2372 perror("Cannot allocate shared memory for curscr");
2374 _exit_process(4, SIGKILL, "exiting from _process_curses_requests");
2377 Xcurscr = (unsigned char*)shmat(shmid_Xcurscr, 0, 0);
2378 memset(Xcurscr, 0, SP->XcurscrSize);
2379 xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF);
2380 memcpy(xc_atrtab, save_atrtab, sizeof(save_atrtab));
2383 /* For PDC_set_title() */
2385 static void _set_title(void)
2387 char title[1024]; /* big enough for window title */
2388 int pos;
2390 if ((XC_read_socket(xc_display_sock, &pos, sizeof(int)) < 0) ||
2391 (XC_read_socket(xc_display_sock, title, pos) < 0))
2393 _exit_process(5, SIGKILL, "exiting from _set_title");
2396 XtVaSetValues(topLevel, XtNtitle, title, NULL);
2399 /* For color_content() */
2401 static void _get_color(void)
2403 XColor *tmp = (XColor *)(Xcurscr + XCURSCR_XCOLOR_OFF);
2404 int index = tmp->pixel;
2405 Colormap cmap = DefaultColormap(XCURSESDISPLAY,
2406 DefaultScreen(XCURSESDISPLAY));
2408 if (index < 0 || index >= MAX_COLORS)
2409 _exit_process(4, SIGKILL, "exiting from _get_color");
2411 tmp->pixel = colors[index];
2412 XQueryColor(XCURSESDISPLAY, cmap, tmp);
2415 /* For init_color() */
2417 static void _set_color(void)
2419 XColor *tmp = (XColor *)(Xcurscr + XCURSCR_XCOLOR_OFF);
2420 int index = tmp->pixel;
2421 Colormap cmap = DefaultColormap(XCURSESDISPLAY,
2422 DefaultScreen(XCURSESDISPLAY));
2424 if (index < 0 || index >= MAX_COLORS)
2425 _exit_process(4, SIGKILL, "exiting from _set_color");
2427 if (XAllocColor(XCURSESDISPLAY, cmap, tmp))
2429 XFreeColors(XCURSESDISPLAY, cmap, colors + index, 1, 0);
2430 colors[index] = tmp->pixel;
2432 _display_screen();
2436 /* For PDC_getclipboard() */
2438 static void _get_selection(Widget w, XtPointer data, Atom *selection,
2439 Atom *type, XtPointer value,
2440 unsigned long *length, int *format)
2442 unsigned char *src = value;
2443 int pos, len = *length;
2445 XC_LOG(("_get_selection() - called\n"));
2447 if (!value && !len)
2449 if (XC_write_display_socket_int(PDC_CLIP_EMPTY) < 0)
2450 _exit_process(4, SIGKILL, "exiting from _get_selection");
2452 else
2454 /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then
2455 contents */
2457 if (XC_write_display_socket_int(PDC_CLIP_SUCCESS) < 0)
2458 _exit_process(4, SIGKILL, "exiting from _get_selection");
2460 if (XC_write_display_socket_int(len) < 0)
2461 _exit_process(4, SIGKILL, "exiting from _get_selection");
2463 for (pos = 0; pos < len; pos++)
2465 #ifdef PDC_WIDE
2466 wchar_t c;
2467 #else
2468 unsigned char c;
2469 #endif
2470 c = *src++;
2472 if (XC_write_socket(xc_display_sock, &c, sizeof(c)) < 0)
2473 _exit_process(4, SIGKILL, "exiting from _get_selection");
2478 #ifdef PDC_WIDE
2479 static void _get_selection_utf8(Widget w, XtPointer data, Atom *selection,
2480 Atom *type, XtPointer value,
2481 unsigned long *length, int *format)
2483 int len = *length;
2485 XC_LOG(("_get_selection_utf8() - called\n"));
2487 if (!*type || !*length)
2489 XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _get_selection,
2490 (XtPointer)NULL, 0);
2491 return;
2494 if (!value && !len)
2496 if (XC_write_display_socket_int(PDC_CLIP_EMPTY) >= 0)
2497 return;
2499 else
2501 wchar_t *wcontents = malloc((len + 1) * sizeof(wchar_t));
2502 char *src = value;
2503 int i = 0;
2505 while (*src && i < (*length))
2507 int retval = _from_utf8(wcontents + i, src, len);
2509 src += retval;
2510 len -= retval;
2511 i++;
2514 wcontents[i] = 0;
2515 len = i;
2517 /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then
2518 contents */
2520 if (XC_write_display_socket_int(PDC_CLIP_SUCCESS) >= 0)
2521 if (XC_write_display_socket_int(len) >= 0)
2522 if (XC_write_socket(xc_display_sock,
2523 wcontents, len * sizeof(wchar_t)) >= 0)
2525 free(wcontents);
2526 return;
2530 _exit_process(4, SIGKILL, "exiting from _get_selection_utf8");
2532 #endif
2534 /* For PDC_setclipboard() */
2536 static void _set_selection(void)
2538 long length, pos;
2539 int status;
2541 if (XC_read_socket(xc_display_sock, &length, sizeof(long)) < 0)
2542 _exit_process(5, SIGKILL, "exiting from _set_selection");
2544 if (length > (long)tmpsel_length)
2546 if (!tmpsel_length)
2547 tmpsel = malloc((length + 1) * sizeof(chtype));
2548 else
2549 tmpsel = realloc(tmpsel, (length + 1) * sizeof(chtype));
2552 if (!tmpsel)
2553 if (XC_write_display_socket_int(PDC_CLIP_MEMORY_ERROR) < 0)
2554 _exit_process(4, SIGKILL, "exiting from _set_selection");
2556 for (pos = 0; pos < length; pos++)
2558 #ifdef PDC_WIDE
2559 wchar_t c;
2560 #else
2561 unsigned char c;
2562 #endif
2563 if (XC_read_socket(xc_display_sock, &c, sizeof(c)) < 0)
2564 _exit_process(5, SIGKILL, "exiting from _set_selection");
2566 tmpsel[pos] = c;
2569 tmpsel_length = length;
2570 tmpsel[length] = 0;
2572 if (XtOwnSelection(topLevel, XA_PRIMARY, CurrentTime,
2573 _convert_proc, _lose_ownership, NULL) == False)
2575 status = PDC_CLIP_ACCESS_ERROR;
2576 free(tmpsel);
2577 tmpsel = NULL;
2578 tmpsel_length = 0;
2580 else
2581 status = PDC_CLIP_SUCCESS;
2583 _selection_off();
2585 if (XC_write_display_socket_int(status) < 0)
2586 _exit_process(4, SIGKILL, "exiting from _set_selection");
2589 /* The curses process is waiting; tell it to continue */
2591 static void _resume_curses(void)
2593 if (XC_write_display_socket_int(CURSES_CONTINUE) < 0)
2594 _exit_process(4, SIGKILL, "exiting from _process_curses_requests");
2597 /* The curses process sent us a message */
2599 static void _process_curses_requests(XtPointer client_data, int *fid,
2600 XtInputId *id)
2602 struct timeval socket_timeout = {0};
2603 int s;
2604 int old_row, new_row;
2605 int old_x, new_x;
2606 int pos, num_cols;
2608 char buf[12]; /* big enough for 2 integers */
2610 XC_LOG(("_process_curses_requests() - called\n"));
2612 if (!received_map_notify)
2613 return;
2615 FD_ZERO(&xc_readfds);
2616 FD_SET(xc_display_sock, &xc_readfds);
2618 if ((s = select(FD_SETSIZE, (FD_SET_CAST)&xc_readfds, NULL,
2619 NULL, &socket_timeout)) < 0)
2620 _exit_process(2, SIGKILL, "exiting from _process_curses_requests"
2621 " - select failed");
2623 if (!s) /* no requests pending - should never happen! */
2624 return;
2626 if (FD_ISSET(xc_display_sock, &xc_readfds))
2628 /* read first integer to determine total message has been
2629 received */
2631 XC_LOG(("_process_curses_requests() - before XC_read_socket()\n"));
2633 if (XC_read_socket(xc_display_sock, &num_cols, sizeof(int)) < 0)
2634 _exit_process(3, SIGKILL, "exiting from _process_curses_requests"
2635 " - first read");
2637 XC_LOG(("_process_curses_requests() - after XC_read_socket()\n"));
2639 after_first_curses_request = TRUE;
2641 switch(num_cols)
2643 case CURSES_EXIT: /* request from curses to stop */
2644 XC_LOG(("CURSES_EXIT received from child\n"));
2645 _exit_process(0, 0, "XCursesProcess requested to exit by child");
2646 break;
2648 case CURSES_BELL:
2649 XC_LOG(("CURSES_BELL received from child\n"));
2650 XBell(XCURSESDISPLAY, 50);
2651 break;
2653 /* request from curses to confirm completion of display */
2655 case CURSES_REFRESH:
2656 XC_LOG(("CURSES_REFRESH received from child\n"));
2657 _refresh_screen();
2658 _resume_curses();
2659 break;
2661 case CURSES_REFRESH_SCROLLBAR:
2662 _refresh_scrollbar();
2663 break;
2665 case CURSES_CURSOR:
2666 XC_LOG(("CURSES_CURSOR received from child\n"));
2668 if (XC_read_socket(xc_display_sock, buf, sizeof(int) * 2) < 0)
2669 _exit_process(5, SIGKILL, "exiting from CURSES_CURSOR "
2670 "_process_curses_requests");
2672 memcpy(&pos, buf, sizeof(int));
2673 old_row = pos & 0xFF;
2674 old_x = pos >> 8;
2676 memcpy(&pos, buf + sizeof(int), sizeof(int));
2677 new_row = pos & 0xFF;
2678 new_x = pos >> 8;
2680 visible_cursor = TRUE;
2681 _display_cursor(old_row, old_x, new_row, new_x);
2682 break;
2684 case CURSES_DISPLAY_CURSOR:
2685 XC_LOG(("CURSES_DISPLAY_CURSOR received from child. Vis now: "));
2686 XC_LOG((visible_cursor ? "1\n" : "0\n"));
2688 /* If the window is not active, ignore this command. The
2689 cursor will stay solid. */
2691 if (window_entered)
2693 if (visible_cursor)
2695 /* Cursor currently ON, turn it off */
2697 int save_visibility = SP->visibility;
2698 SP->visibility = 0;
2699 _redraw_cursor();
2700 SP->visibility = save_visibility;
2701 visible_cursor = FALSE;
2703 else
2705 /* Cursor currently OFF, turn it on */
2707 _redraw_cursor();
2708 visible_cursor = TRUE;
2712 break;
2714 case CURSES_TITLE:
2715 XC_LOG(("CURSES_TITLE received from child\n"));
2716 _set_title();
2717 break;
2719 case CURSES_RESIZE:
2720 XC_LOG(("CURSES_RESIZE received from child\n"));
2721 _resize();
2722 _resume_curses();
2723 break;
2725 case CURSES_GET_SELECTION:
2726 XC_LOG(("CURSES_GET_SELECTION received from child\n"));
2728 _resume_curses();
2730 XtGetSelectionValue(topLevel, XA_PRIMARY,
2731 #ifdef PDC_WIDE
2732 XA_UTF8_STRING(XtDisplay(topLevel)),
2733 _get_selection_utf8,
2734 #else
2735 XA_STRING, _get_selection,
2736 #endif
2737 (XtPointer)NULL, 0);
2739 break;
2741 case CURSES_SET_SELECTION:
2742 XC_LOG(("CURSES_SET_SELECTION received from child\n"));
2743 _set_selection();
2744 break;
2746 case CURSES_CLEAR_SELECTION:
2747 XC_LOG(("CURSES_CLEAR_SELECTION received from child\n"));
2748 _resume_curses();
2749 _selection_off();
2750 break;
2752 case CURSES_GET_COLOR:
2753 XC_LOG(("CURSES_GET_COLOR recieved from child\n"));
2754 _get_color();
2755 _resume_curses();
2756 break;
2758 case CURSES_SET_COLOR:
2759 XC_LOG(("CURSES_SET_COLOR recieved from child\n"));
2760 _set_color();
2761 _resume_curses();
2762 break;
2764 default:
2765 PDC_LOG(("%s:Unknown request %d\n", XCLOGMSG, num_cols));
2770 static void _handle_structure_notify(Widget w, XtPointer client_data,
2771 XEvent *event, Boolean *unused)
2773 XC_LOG(("_handle_structure_notify() - called\n"));
2775 switch(event->type)
2777 case ConfigureNotify:
2778 XC_LOG(("ConfigureNotify received\n"));
2780 /* Window has been resized, change width and height to send to
2781 place_text and place_graphics in next Expose. Also will need
2782 to kill (SIGWINCH) curses process if screen size changes. */
2784 resize_window_width = event->xconfigure.width;
2785 resize_window_height = event->xconfigure.height;
2787 after_first_curses_request = FALSE;
2789 #ifdef SIGWINCH
2790 SP->resized = 1;
2792 kill(xc_otherpid, SIGWINCH);
2793 #endif
2794 _send_key_to_curses(KEY_RESIZE, NULL, TRUE);
2795 break;
2797 case MapNotify:
2798 XC_LOG(("MapNotify received\n"));
2800 received_map_notify = 1;
2802 _draw_border();
2803 break;
2805 default:
2806 PDC_LOG(("%s:_handle_structure_notify - unknown event %d\n",
2807 XCLOGMSG, event->type));
2811 static RETSIGTYPE _handle_signals(int signo)
2813 int flag = CURSES_EXIT;
2815 PDC_LOG(("%s:_handle_signals() - called: %d\n", XCLOGMSG, signo));
2817 /* Patch by: Georg Fuchs */
2819 XCursesSetSignal(signo, _handle_signals);
2821 #ifdef SIGTSTP
2822 if (signo == SIGTSTP)
2824 pause();
2825 return;
2827 #endif
2828 #ifdef SIGCONT
2829 if (signo == SIGCONT)
2830 return;
2831 #endif
2832 #ifdef SIGCLD
2833 if (signo == SIGCLD)
2834 return;
2835 #endif
2836 #ifdef SIGTTIN
2837 if (signo == SIGTTIN)
2838 return;
2839 #endif
2840 #ifdef SIGWINCH
2841 if (signo == SIGWINCH)
2842 return;
2843 #endif
2845 /* End of patch by: Georg Fuchs */
2847 XCursesSetSignal(signo, SIG_IGN);
2849 /* Send a CURSES_EXIT to myself */
2851 if (XC_write_socket(xc_exit_sock, &flag, sizeof(int)) < 0)
2852 _exit_process(7, signo, "exiting from _handle_signals");
2855 #ifdef PDC_XIM
2856 static void _dummy_handler(Widget w, XtPointer client_data,
2857 XEvent *event, Boolean *unused)
2860 #endif
2862 int XCursesSetupX(int argc, char *argv[])
2864 char *myargv[] = {"PDCurses", NULL};
2865 extern bool sb_started;
2867 int italic_font_valid;
2868 XColor pointerforecolor, pointerbackcolor;
2869 XrmValue rmfrom, rmto;
2870 int i = 0;
2871 int minwidth, minheight;
2873 XC_LOG(("XCursesSetupX called\n"));
2875 if (!argv)
2877 argv = myargv;
2878 argc = 1;
2881 program_name = argv[0];
2883 /* Keep open the 'write' end of the socket so the XCurses process
2884 can send a CURSES_EXIT to itself from within the signal handler */
2886 xc_exit_sock = xc_display_sockets[0];
2887 xc_display_sock = xc_display_sockets[1];
2889 close(xc_key_sockets[0]);
2890 xc_key_sock = xc_key_sockets[1];
2892 /* Trap all signals when XCurses is the child process, but only if
2893 they haven't already been ignored by the application. */
2895 for (i = 0; i < PDC_MAX_SIGNALS; i++)
2896 if (XCursesSetSignal(i, _handle_signals) == SIG_IGN)
2897 XCursesSetSignal(i, SIG_IGN);
2899 /* Start defining X Toolkit things */
2901 #if XtSpecificationRelease > 4
2902 XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL);
2903 #endif
2905 /* Exit if no DISPLAY variable set */
2907 if (!getenv("DISPLAY"))
2909 fprintf(stderr, "Error: no DISPLAY variable set\n");
2910 kill(xc_otherpid, SIGKILL);
2911 return ERR;
2914 /* Initialise the top level widget */
2916 topLevel = XtVaAppInitialize(&app_context, class_name, options,
2917 XtNumber(options), &argc, argv, NULL, NULL);
2919 XtVaGetApplicationResources(topLevel, &xc_app_data, app_resources,
2920 XtNumber(app_resources), NULL);
2922 /* Check application resource values here */
2924 font_width = xc_app_data.normalFont->max_bounds.rbearing -
2925 xc_app_data.normalFont->min_bounds.lbearing;
2927 font_height = xc_app_data.normalFont->max_bounds.ascent +
2928 xc_app_data.normalFont->max_bounds.descent;
2930 font_ascent = xc_app_data.normalFont->max_bounds.ascent;
2931 font_descent = xc_app_data.normalFont->max_bounds.descent;
2933 /* Check that the italic font and normal fonts are the same size */
2934 /* This appears backwards */
2936 italic_font_valid = font_width !=
2937 xc_app_data.italicFont->max_bounds.rbearing -
2938 xc_app_data.italicFont->min_bounds.lbearing ||
2939 font_height !=
2940 xc_app_data.italicFont->max_bounds.ascent +
2941 xc_app_data.italicFont->max_bounds.descent;
2943 /* Calculate size of display window */
2945 XCursesCOLS = xc_app_data.cols;
2946 XCursesLINES = xc_app_data.lines;
2948 window_width = font_width * XCursesCOLS +
2949 2 * xc_app_data.borderWidth;
2951 window_height = font_height * XCursesLINES +
2952 2 * xc_app_data.borderWidth;
2954 minwidth = font_width * 2 + xc_app_data.borderWidth * 2;
2955 minheight = font_height * 2 + xc_app_data.borderWidth * 2;
2957 /* Set up the icon for the application; the default is an internal
2958 one for PDCurses. Then set various application level resources. */
2960 _get_icon();
2962 #ifdef HAVE_XPM_H
2963 if (xc_app_data.pixmap && xc_app_data.pixmap[0])
2964 XtVaSetValues(topLevel, XtNminWidth, minwidth, XtNminHeight,
2965 minheight, XtNbaseWidth, xc_app_data.borderWidth * 2,
2966 XtNbaseHeight, xc_app_data.borderWidth * 2,
2967 XtNiconPixmap, icon_pixmap,
2968 XtNiconMask, icon_pixmap_mask, NULL);
2969 else
2970 #endif
2971 XtVaSetValues(topLevel, XtNminWidth, minwidth, XtNminHeight,
2972 minheight, XtNbaseWidth, xc_app_data.borderWidth * 2,
2973 XtNbaseHeight, xc_app_data.borderWidth * 2,
2974 XtNiconPixmap, icon_bitmap, NULL);
2976 /* Create a BOX widget in which to draw */
2978 if (xc_app_data.scrollbarWidth && sb_started)
2980 scrollBox = XtVaCreateManagedWidget(program_name,
2981 scrollBoxWidgetClass, topLevel, XtNwidth,
2982 window_width + xc_app_data.scrollbarWidth,
2983 XtNheight, window_height + xc_app_data.scrollbarWidth,
2984 XtNwidthInc, font_width, XtNheightInc, font_height, NULL);
2986 drawing = XtVaCreateManagedWidget(program_name,
2987 boxWidgetClass, scrollBox, XtNwidth,
2988 window_width, XtNheight, window_height, XtNwidthInc,
2989 font_width, XtNheightInc, font_height, NULL);
2991 scrollVert = XtVaCreateManagedWidget("scrollVert",
2992 scrollbarWidgetClass, scrollBox, XtNorientation,
2993 XtorientVertical, XtNheight, window_height, XtNwidth,
2994 xc_app_data.scrollbarWidth, NULL);
2996 XtAddCallback(scrollVert, XtNscrollProc, _scroll_up_down, drawing);
2997 XtAddCallback(scrollVert, XtNjumpProc, _thumb_up_down, drawing);
2999 scrollHoriz = XtVaCreateManagedWidget("scrollHoriz",
3000 scrollbarWidgetClass, scrollBox, XtNorientation,
3001 XtorientHorizontal, XtNwidth, window_width, XtNheight,
3002 xc_app_data.scrollbarWidth, NULL);
3004 XtAddCallback(scrollHoriz, XtNscrollProc, _scroll_left_right, drawing);
3005 XtAddCallback(scrollHoriz, XtNjumpProc, _thumb_left_right, drawing);
3007 else
3009 drawing = XtVaCreateManagedWidget(program_name, boxWidgetClass,
3010 topLevel, XtNwidth, window_width, XtNheight, window_height,
3011 XtNwidthInc, font_width, XtNheightInc, font_height, NULL);
3013 XtVaSetValues(topLevel, XtNwidthInc, font_width, XtNheightInc,
3014 font_height, NULL);
3017 /* Process any default translations */
3019 XtAugmentTranslations(drawing,
3020 XtParseTranslationTable(default_translations));
3021 XtAppAddActions(app_context, action_table, XtNumber(action_table));
3023 /* Process the supplied colors */
3025 _initialize_colors();
3027 /* Determine text cursor alignment from resources */
3029 if (!strcmp(xc_app_data.textCursor, "vertical"))
3030 vertical_cursor = TRUE;
3032 /* Now have LINES and COLS. Set these in the shared SP so the curses
3033 program can find them. */
3035 LINES = XCursesLINES;
3036 COLS = XCursesCOLS;
3038 if ((shmidSP = shmget(shmkeySP, sizeof(SCREEN) + XCURSESSHMMIN,
3039 0700 | IPC_CREAT)) < 0)
3041 perror("Cannot allocate shared memory for SCREEN");
3042 kill(xc_otherpid, SIGKILL);
3043 return ERR;
3046 SP = (SCREEN*)shmat(shmidSP, 0, 0);
3047 memset(SP, 0, sizeof(SCREEN));
3048 SP->XcurscrSize = XCURSCR_SIZE;
3049 SP->lines = XCursesLINES;
3050 SP->cols = XCursesCOLS;
3052 SP->mouse_wait = xc_app_data.clickPeriod;
3053 SP->audible = TRUE;
3055 PDC_LOG(("%s:SHM size for curscr %d\n", XCLOGMSG, SP->XcurscrSize));
3057 if ((shmid_Xcurscr = shmget(shmkey_Xcurscr, SP->XcurscrSize +
3058 XCURSESSHMMIN, 0700 | IPC_CREAT)) < 0)
3060 perror("Cannot allocate shared memory for curscr");
3061 kill(xc_otherpid, SIGKILL);
3062 shmdt((char *)SP);
3063 shmctl(shmidSP, IPC_RMID, 0);
3064 return ERR;
3067 Xcurscr = (unsigned char *)shmat(shmid_Xcurscr, 0, 0);
3068 memset(Xcurscr, 0, SP->XcurscrSize);
3069 xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF);
3071 PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n",
3072 XCLOGMSG, shmid_Xcurscr, shmkey_Xcurscr, LINES, COLS));
3074 /* Add Event handlers to the drawing widget */
3076 XtAddEventHandler(drawing, ExposureMask, False, _handle_expose, NULL);
3077 XtAddEventHandler(drawing, StructureNotifyMask, False,
3078 _handle_structure_notify, NULL);
3079 XtAddEventHandler(drawing, EnterWindowMask | LeaveWindowMask, False,
3080 _handle_enter_leave, NULL);
3081 XtAddEventHandler(topLevel, 0, True, _handle_nonmaskable, NULL);
3083 /* Add input handler from xc_display_sock (requests from curses
3084 program) */
3086 XtAppAddInput(app_context, xc_display_sock, (XtPointer)XtInputReadMask,
3087 _process_curses_requests, NULL);
3089 /* If there is a cursorBlink resource, start the Timeout event */
3091 if (xc_app_data.cursorBlinkRate)
3092 XtAppAddTimeOut(app_context, xc_app_data.cursorBlinkRate,
3093 _blink_cursor, NULL);
3095 /* Leave telling the curses process that it can start to here so
3096 that when the curses process makes a request, the Xcurses
3097 process can service the request. */
3099 XC_write_display_socket_int(CURSES_CHILD);
3101 XtRealizeWidget(topLevel);
3103 /* Handle trapping of the WM_DELETE_WINDOW property */
3105 wm_atom[0] = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", False);
3107 XSetWMProtocols(XtDisplay(topLevel), XtWindow(topLevel), wm_atom, 1);
3109 /* Create the Graphics Context for drawing. This MUST be done AFTER
3110 the associated widget has been realized. */
3112 XC_LOG(("before _get_gc\n"));
3114 _get_gc(&normal_gc, xc_app_data.normalFont, COLOR_WHITE, COLOR_BLACK);
3116 _get_gc(&italic_gc, italic_font_valid ? xc_app_data.italicFont :
3117 xc_app_data.normalFont, COLOR_WHITE, COLOR_BLACK);
3119 _get_gc(&block_cursor_gc, xc_app_data.normalFont,
3120 COLOR_BLACK, COLOR_CURSOR);
3122 _get_gc(&rect_cursor_gc, xc_app_data.normalFont,
3123 COLOR_CURSOR, COLOR_BLACK);
3125 _get_gc(&border_gc, xc_app_data.normalFont, COLOR_BORDER, COLOR_BLACK);
3127 XSetLineAttributes(XCURSESDISPLAY, rect_cursor_gc, 2,
3128 LineSolid, CapButt, JoinMiter);
3130 XSetLineAttributes(XCURSESDISPLAY, border_gc, xc_app_data.borderWidth,
3131 LineSolid, CapButt, JoinMiter);
3133 /* Set the cursor for the application */
3135 XDefineCursor(XCURSESDISPLAY, XCURSESWIN, xc_app_data.pointer);
3136 rmfrom.size = sizeof(Pixel);
3137 rmto.size = sizeof(XColor);
3139 rmto.addr = (XPointer)&pointerforecolor;
3140 rmfrom.addr = (XPointer)&(xc_app_data.pointerForeColor);
3141 XtConvertAndStore(drawing, XtRPixel, &rmfrom, XtRColor, &rmto);
3143 rmfrom.size = sizeof(Pixel);
3144 rmto.size = sizeof(XColor);
3146 rmfrom.addr = (XPointer)&(xc_app_data.pointerBackColor);
3147 rmto.addr = (XPointer)&pointerbackcolor;
3148 XtConvertAndStore(drawing, XtRPixel, &rmfrom, XtRColor, &rmto);
3150 XRecolorCursor(XCURSESDISPLAY, xc_app_data.pointer,
3151 &pointerforecolor, &pointerbackcolor);
3153 #ifndef PDC_XIM
3155 /* Convert the supplied compose key to a Keysym */
3157 compose_key = XStringToKeysym(xc_app_data.composeKey);
3159 if (compose_key && IsModifierKey(compose_key))
3161 int i, j;
3162 KeyCode *kcp;
3163 XModifierKeymap *map;
3164 KeyCode compose_keycode = XKeysymToKeycode(XCURSESDISPLAY, compose_key);
3166 map = XGetModifierMapping(XCURSESDISPLAY);
3167 kcp = map->modifiermap;
3169 for (i = 0; i < 8; i++)
3171 for (j = 0; j < map->max_keypermod; j++, kcp++)
3173 if (!*kcp)
3174 continue;
3176 if (compose_keycode == *kcp)
3178 compose_mask = state_mask[i];
3179 break;
3183 if (compose_mask)
3184 break;
3187 XFreeModifiermap(map);
3190 #else
3191 Xim = XOpenIM(XCURSESDISPLAY, NULL, NULL, NULL);
3193 if (Xim)
3195 Xic = XCreateIC(Xim, XNInputStyle,
3196 XIMPreeditNothing | XIMStatusNothing,
3197 XNClientWindow, XCURSESWIN, NULL);
3200 if (Xic)
3202 long im_event_mask;
3204 XGetICValues(Xic, XNFilterEvents, &im_event_mask, NULL);
3205 if (im_event_mask)
3206 XtAddEventHandler(drawing, im_event_mask, False,
3207 _dummy_handler, NULL);
3209 XSetICFocus(Xic);
3211 else
3213 perror("ERROR: Cannot create input context");
3214 kill(xc_otherpid, SIGKILL);
3215 shmdt((char *)SP);
3216 shmdt((char *)Xcurscr);
3217 shmctl(shmidSP, IPC_RMID, 0);
3218 shmctl(shmid_Xcurscr, IPC_RMID, 0);
3219 return ERR;
3222 #endif
3224 /* Wait for events */
3226 XtAppMainLoop(app_context);
3227 return OK; /* won't get here */