diff options
Diffstat (limited to 'payloads/libpayload/curses/PDCurses/x11/x11.c')
-rw-r--r-- | payloads/libpayload/curses/PDCurses/x11/x11.c | 3229 |
1 files changed, 3229 insertions, 0 deletions
diff --git a/payloads/libpayload/curses/PDCurses/x11/x11.c b/payloads/libpayload/curses/PDCurses/x11/x11.c new file mode 100644 index 0000000000..69c3199b54 --- /dev/null +++ b/payloads/libpayload/curses/PDCurses/x11/x11.c @@ -0,0 +1,3229 @@ +/* Public Domain Curses */ + +#include "pdcx11.h" + +RCSID("$Id: x11.c,v 1.94 2008/07/14 04:33:26 wmcbrine Exp $") + +#ifdef HAVE_DECKEYSYM_H +# include <DECkeysym.h> +#endif + +#ifdef HAVE_SUNKEYSYM_H +# include <Sunkeysym.h> +#endif + +#ifdef HAVE_XPM_H +# include <xpm.h> +#endif + +#if defined PDC_XIM +# include <Xlocale.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#ifndef XPOINTER_TYPEDEFED +typedef char * XPointer; +#endif + +#ifndef MAX_PATH +# define MAX_PATH 256 +#endif + +XCursesAppData xc_app_data; + +#if NeedWidePrototypes +# define PDC_SCROLLBAR_TYPE double +#else +# define PDC_SCROLLBAR_TYPE float +#endif + +#define MAX_COLORS 16 /* maximum of "normal" colors */ +#define COLOR_CURSOR MAX_COLORS /* color of cursor */ +#define COLOR_BORDER MAX_COLORS + 1 /* color of border */ + +#define XCURSESDISPLAY (XtDisplay(drawing)) +#define XCURSESWIN (XtWindow(drawing)) + +/* Default icons for XCurses applications. */ + +#include "big_icon.xbm" +#include "little_icon.xbm" + +static void _selection_off(void); +static void _display_cursor(int, int, int, int); +static void _redraw_cursor(void); +static void _exit_process(int, int, char *); +static void _send_key_to_curses(unsigned long, MOUSE_STATUS *, bool); + +static void XCursesButton(Widget, XEvent *, String *, Cardinal *); +static void XCursesHandleString(Widget, XEvent *, String *, Cardinal *); +static void XCursesKeyPress(Widget, XEvent *, String *, Cardinal *); +static void XCursesPasteSelection(Widget, XButtonEvent *); + +static struct +{ + KeySym keycode; + bool numkeypad; + unsigned short normal; + unsigned short shifted; + unsigned short control; + unsigned short alt; +} key_table[] = +{ +/* keycode keypad normal shifted control alt*/ + {XK_Left, FALSE, KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT}, + {XK_Right, FALSE, KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT}, + {XK_Up, FALSE, KEY_UP, KEY_SUP, CTL_UP, ALT_UP}, + {XK_Down, FALSE, KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN}, + {XK_Home, FALSE, KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME}, +/* Sun Type 4 keyboard */ + {XK_R7, FALSE, KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME}, + {XK_End, FALSE, KEY_END, KEY_SEND, CTL_END, ALT_END}, +/* Sun Type 4 keyboard */ + {XK_R13, FALSE, KEY_END, KEY_SEND, CTL_END, ALT_END}, + {XK_Prior, FALSE, KEY_PPAGE, KEY_SPREVIOUS,CTL_PGUP, ALT_PGUP}, +/* Sun Type 4 keyboard */ + {XK_R9, FALSE, KEY_PPAGE, KEY_SPREVIOUS,CTL_PGUP, ALT_PGUP}, + {XK_Next, FALSE, KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN}, +/* Sun Type 4 keyboard */ + {XK_R15, FALSE, KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN}, + {XK_Insert, FALSE, KEY_IC, KEY_SIC, CTL_INS, ALT_INS}, + {XK_Delete, FALSE, KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL}, + {XK_F1, FALSE, KEY_F(1), KEY_F(13), KEY_F(25), KEY_F(37)}, + {XK_F2, FALSE, KEY_F(2), KEY_F(14), KEY_F(26), KEY_F(38)}, + {XK_F3, FALSE, KEY_F(3), KEY_F(15), KEY_F(27), KEY_F(39)}, + {XK_F4, FALSE, KEY_F(4), KEY_F(16), KEY_F(28), KEY_F(40)}, + {XK_F5, FALSE, KEY_F(5), KEY_F(17), KEY_F(29), KEY_F(41)}, + {XK_F6, FALSE, KEY_F(6), KEY_F(18), KEY_F(30), KEY_F(42)}, + {XK_F7, FALSE, KEY_F(7), KEY_F(19), KEY_F(31), KEY_F(43)}, + {XK_F8, FALSE, KEY_F(8), KEY_F(20), KEY_F(32), KEY_F(44)}, + {XK_F9, FALSE, KEY_F(9), KEY_F(21), KEY_F(33), KEY_F(45)}, + {XK_F10, FALSE, KEY_F(10), KEY_F(22), KEY_F(34), KEY_F(46)}, + {XK_F11, FALSE, KEY_F(11), KEY_F(23), KEY_F(35), KEY_F(47)}, + {XK_F12, FALSE, KEY_F(12), KEY_F(24), KEY_F(36), KEY_F(48)}, + {XK_F13, FALSE, KEY_F(13), KEY_F(25), KEY_F(37), KEY_F(49)}, + {XK_F14, FALSE, KEY_F(14), KEY_F(26), KEY_F(38), KEY_F(50)}, + {XK_F15, FALSE, KEY_F(15), KEY_F(27), KEY_F(39), KEY_F(51)}, + {XK_F16, FALSE, KEY_F(16), KEY_F(28), KEY_F(40), KEY_F(52)}, + {XK_F17, FALSE, KEY_F(17), KEY_F(29), KEY_F(41), KEY_F(53)}, + {XK_F18, FALSE, KEY_F(18), KEY_F(30), KEY_F(42), KEY_F(54)}, + {XK_F19, FALSE, KEY_F(19), KEY_F(31), KEY_F(43), KEY_F(55)}, + {XK_F20, FALSE, KEY_F(20), KEY_F(32), KEY_F(44), KEY_F(56)}, + {XK_BackSpace, FALSE, 0x08, 0x08, CTL_BKSP, ALT_BKSP}, + {XK_Tab, FALSE, 0x09, KEY_BTAB, CTL_TAB, ALT_TAB}, + {XK_Select, FALSE, KEY_SELECT, KEY_SELECT, KEY_SELECT, KEY_SELECT}, + {XK_Print, FALSE, KEY_PRINT, KEY_SPRINT, KEY_PRINT, KEY_PRINT}, + {XK_Find, FALSE, KEY_FIND, KEY_SFIND, KEY_FIND, KEY_FIND}, + {XK_Pause, FALSE, KEY_SUSPEND, KEY_SSUSPEND, KEY_SUSPEND, KEY_SUSPEND}, + {XK_Clear, FALSE, KEY_CLEAR, KEY_CLEAR, KEY_CLEAR, KEY_CLEAR}, + {XK_Cancel, FALSE, KEY_CANCEL, KEY_SCANCEL, KEY_CANCEL, KEY_CANCEL}, + {XK_Break, FALSE, KEY_BREAK, KEY_BREAK, KEY_BREAK, KEY_BREAK}, + {XK_Help, FALSE, KEY_HELP, KEY_SHELP, KEY_LHELP, KEY_HELP}, + {XK_L4, FALSE, KEY_UNDO, KEY_SUNDO, KEY_UNDO, KEY_UNDO}, + {XK_L6, FALSE, KEY_COPY, KEY_SCOPY, KEY_COPY, KEY_COPY}, + {XK_L9, FALSE, KEY_FIND, KEY_SFIND, KEY_FIND, KEY_FIND}, + {XK_Menu, FALSE, KEY_OPTIONS, KEY_SOPTIONS, KEY_OPTIONS, KEY_OPTIONS}, +#ifdef HAVE_SUNKEYSYM_H + {SunXK_F36, FALSE, KEY_F(41), KEY_F(43), KEY_F(45), KEY_F(47)}, + {SunXK_F37, FALSE, KEY_F(42), KEY_F(44), KEY_F(46), KEY_F(48)}, +#endif +#ifdef HAVE_DECKEYSYM_H + {DXK_Remove, FALSE, KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL}, +#endif + {XK_Escape, FALSE, 0x1B, 0x1B, 0x1B, ALT_ESC}, + {XK_KP_Enter, TRUE, PADENTER, PADENTER, CTL_PADENTER,ALT_PADENTER}, + {XK_KP_Add, TRUE, PADPLUS, '+', CTL_PADPLUS, ALT_PADPLUS}, + {XK_KP_Subtract,TRUE, PADMINUS, '-', CTL_PADMINUS,ALT_PADMINUS}, + {XK_KP_Multiply,TRUE, PADSTAR, '*', CTL_PADSTAR, ALT_PADSTAR}, +/* Sun Type 4 keyboard */ + {XK_R6, TRUE, PADSTAR, '*', CTL_PADSTAR, ALT_PADSTAR}, + {XK_KP_Divide, TRUE, PADSLASH, '/', CTL_PADSLASH,ALT_PADSLASH}, +/* Sun Type 4 keyboard */ + {XK_R5, TRUE, PADSLASH, '/', CTL_PADSLASH,ALT_PADSLASH}, + {XK_KP_Decimal,TRUE, PADSTOP, '.', CTL_PADSTOP, ALT_PADSTOP}, + {XK_KP_0, TRUE, PAD0, '0', CTL_PAD0, ALT_PAD0}, + {XK_KP_1, TRUE, KEY_C1, '1', CTL_PAD1, ALT_PAD1}, + {XK_KP_2, TRUE, KEY_C2, '2', CTL_PAD2, ALT_PAD2}, + {XK_KP_3, TRUE, KEY_C3, '3', CTL_PAD3, ALT_PAD3}, + {XK_KP_4, TRUE, KEY_B1, '4', CTL_PAD4, ALT_PAD4}, + {XK_KP_5, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5}, +/* Sun Type 4 keyboard */ + {XK_R11, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5}, + {XK_KP_6, TRUE, KEY_B3, '6', CTL_PAD6, ALT_PAD6}, + {XK_KP_7, TRUE, KEY_A1, '7', CTL_PAD7, ALT_PAD7}, + {XK_KP_8, TRUE, KEY_A2, '8', CTL_PAD8, ALT_PAD8}, + {XK_KP_9, TRUE, KEY_A3, '9', CTL_PAD9, ALT_PAD9}, +/* the following added to support Sun Type 5 keyboards */ + {XK_F21, FALSE, KEY_SUSPEND, KEY_SSUSPEND, KEY_SUSPEND, KEY_SUSPEND}, + {XK_F22, FALSE, KEY_PRINT, KEY_SPRINT, KEY_PRINT, KEY_PRINT}, + {XK_F24, TRUE, PADMINUS, '-', CTL_PADMINUS,ALT_PADMINUS}, +/* Sun Type 4 keyboard */ + {XK_F25, TRUE, PADSLASH, '/', CTL_PADSLASH,ALT_PADSLASH}, +/* Sun Type 4 keyboard */ + {XK_F26, TRUE, PADSTAR, '*', CTL_PADSTAR, ALT_PADSTAR}, + {XK_F27, TRUE, KEY_A1, '7', CTL_PAD7, ALT_PAD7}, + {XK_F29, TRUE, KEY_A3, '9', CTL_PAD9, ALT_PAD9}, + {XK_F31, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5}, + {XK_F35, TRUE, KEY_C3, '3', CTL_PAD3, ALT_PAD3}, +#ifdef HAVE_XK_KP_DELETE + {XK_KP_Delete, TRUE, PADSTOP, '.', CTL_PADSTOP, ALT_PADSTOP}, +#endif +#ifdef HAVE_XK_KP_INSERT + {XK_KP_Insert, TRUE, PAD0, '0', CTL_PAD0, ALT_PAD0}, +#endif +#ifdef HAVE_XK_KP_END + {XK_KP_End, TRUE, KEY_C1, '1', CTL_PAD1, ALT_PAD1}, +#endif +#ifdef HAVE_XK_KP_DOWN + {XK_KP_Down, TRUE, KEY_C2, '2', CTL_PAD2, ALT_PAD2}, +#endif +#ifdef HAVE_XK_KP_NEXT + {XK_KP_Next, TRUE, KEY_C3, '3', CTL_PAD3, ALT_PAD3}, +#endif +#ifdef HAVE_XK_KP_LEFT + {XK_KP_Left, TRUE, KEY_B1, '4', CTL_PAD4, ALT_PAD4}, +#endif +#ifdef HAVE_XK_KP_BEGIN + {XK_KP_Begin, TRUE, KEY_B2, '5', CTL_PAD5, ALT_PAD5}, +#endif +#ifdef HAVE_XK_KP_RIGHT + {XK_KP_Right, TRUE, KEY_B3, '6', CTL_PAD6, ALT_PAD6}, +#endif +#ifdef HAVE_XK_KP_HOME + {XK_KP_Home, TRUE, KEY_A1, '7', CTL_PAD7, ALT_PAD7}, +#endif +#ifdef HAVE_XK_KP_UP + {XK_KP_Up, TRUE, KEY_A2, '8', CTL_PAD8, ALT_PAD8}, +#endif +#ifdef HAVE_XK_KP_PRIOR + {XK_KP_Prior, TRUE, KEY_A3, '9', CTL_PAD9, ALT_PAD9}, +#endif + {0, 0, 0, 0, 0, 0} +}; + +#ifndef PDC_XIM +# include "compose.h" +#endif + +#define BITMAPDEPTH 1 + +unsigned long pdc_key_modifiers = 0L; + +static GC normal_gc, block_cursor_gc, rect_cursor_gc, italic_gc, border_gc; +static int font_height, font_width, font_ascent, font_descent, + window_width, window_height; +static int resize_window_width = 0, resize_window_height = 0; +static char *bitmap_file = NULL; +#ifdef HAVE_XPM_H +static char *pixmap_file = NULL; +#endif +static KeySym keysym = 0; + +static int state_mask[8] = +{ + ShiftMask, + LockMask, + ControlMask, + Mod1Mask, + Mod2Mask, + Mod3Mask, + Mod4Mask, + Mod5Mask +}; + +static Atom wm_atom[2]; +static String class_name = "XCurses"; +static XtAppContext app_context; +static Widget topLevel, drawing, scrollBox, scrollVert, scrollHoriz; +static int received_map_notify = 0; +static bool mouse_selection = FALSE; +static chtype *tmpsel = NULL; +static unsigned long tmpsel_length = 0; +static int selection_start_x = 0, selection_start_y = 0, + selection_end_x = 0, selection_end_y = 0; +static Pixmap icon_bitmap; +#ifdef HAVE_XPM_H +static Pixmap icon_pixmap; +static Pixmap icon_pixmap_mask; +#endif +static bool visible_cursor = FALSE; +static bool window_entered = TRUE; +static char *program_name; + +/* Macros just for app_resources */ + +#ifdef PDC_WIDE +# define DEFFONT "-misc-fixed-medium-r-normal--20-200-75-75-c-100-iso10646-1" +#else +# define DEFFONT "7x13" +#endif + +#define APPDATAOFF(n) XtOffsetOf(XCursesAppData, n) + +#define RINT(name1, name2, value) { \ + #name1, #name2, XtRInt, \ + sizeof(int), APPDATAOFF(name1), XtRImmediate, \ + (XtPointer)value \ + } + +#define RPIXEL(name1, name2, value) { \ + #name1, #name2, XtRPixel, \ + sizeof(Pixel), APPDATAOFF(name1), XtRString, \ + (XtPointer)#value \ + } + +#define RCOLOR(name, value) RPIXEL(color##name, Color##name, value) + + +#define RSTRINGP(name1, name2, param) { \ + #name1, #name2, XtRString, \ + MAX_PATH, APPDATAOFF(name1), XtRString, (XtPointer)param \ + } + +#define RSTRING(name1, name2) RSTRINGP(name1, name2, "") + +#define RFONT(name1, name2, value) { \ + #name1, #name2, XtRFontStruct, \ + sizeof(XFontStruct), APPDATAOFF(name1), XtRString, \ + (XtPointer)value \ + } + +#define RCURSOR(name1, name2, value) { \ + #name1, #name2, XtRCursor, \ + sizeof(Cursor), APPDATAOFF(name1), XtRString, \ + (XtPointer)#value \ + } + +static XtResource app_resources[] = +{ + RINT(lines, Lines, 24), + RINT(cols, Cols, 80), + + RPIXEL(cursorColor, CursorColor, Red), + + RCOLOR(Black, Black), + RCOLOR(Red, red3), + RCOLOR(Green, green3), + RCOLOR(Yellow, yellow3), + RCOLOR(Blue, blue3), + RCOLOR(Magenta, magenta3), + RCOLOR(Cyan, cyan3), + RCOLOR(White, Grey), + + RCOLOR(BoldBlack, grey40), + RCOLOR(BoldRed, red1), + RCOLOR(BoldGreen, green1), + RCOLOR(BoldYellow, yellow1), + RCOLOR(BoldBlue, blue1), + RCOLOR(BoldMagenta, magenta1), + RCOLOR(BoldCyan, cyan1), + RCOLOR(BoldWhite, White), + + RFONT(normalFont, NormalFont, DEFFONT), + RFONT(italicFont, ItalicFont, DEFFONT), + + RSTRING(bitmap, Bitmap), +#ifdef HAVE_XPM_H + RSTRING(pixmap, Pixmap), +#endif + RSTRINGP(composeKey, ComposeKey, "Multi_key"), + + RCURSOR(pointer, Pointer, xterm), + + RPIXEL(pointerForeColor, PointerForeColor, Black), + RPIXEL(pointerBackColor, PointerBackColor, White), + + RINT(shmmin, Shmmin, 0), + RINT(borderWidth, BorderWidth, 0), + + RPIXEL(borderColor, BorderColor, Black), + + RINT(doubleClickPeriod, DoubleClickPeriod, (PDC_CLICK_PERIOD * 2)), + RINT(clickPeriod, ClickPeriod, PDC_CLICK_PERIOD), + RINT(scrollbarWidth, ScrollbarWidth, 15), + RINT(cursorBlinkRate, CursorBlinkRate, 0), + + RSTRING(textCursor, TextCursor) +}; + +#undef RCURSOR +#undef RFONT +#undef RSTRING +#undef RCOLOR +#undef RPIXEL +#undef RINT +#undef APPDATAOFF +#undef DEFFONT + +/* Macros for options */ + +#define COPT(name) {"-" #name, "*" #name, XrmoptionSepArg, NULL} +#define CCOLOR(name) COPT(color##name) + +static XrmOptionDescRec options[] = +{ + COPT(lines), COPT(cols), COPT(normalFont), COPT(italicFont), + COPT(bitmap), +#ifdef HAVE_XPM_H + COPT(pixmap), +#endif + COPT(pointer), COPT(shmmin), COPT(composeKey), COPT(clickPeriod), + COPT(doubleClickPeriod), COPT(scrollbarWidth), + COPT(pointerForeColor), COPT(pointerBackColor), + COPT(cursorBlinkRate), COPT(cursorColor), COPT(textCursor), + + CCOLOR(Black), CCOLOR(Red), CCOLOR(Green), CCOLOR(Yellow), + CCOLOR(Blue), CCOLOR(Magenta), CCOLOR(Cyan), CCOLOR(White), + + CCOLOR(BoldBlack), CCOLOR(BoldRed), CCOLOR(BoldGreen), + CCOLOR(BoldYellow), CCOLOR(BoldBlue), CCOLOR(BoldMagenta), + CCOLOR(BoldCyan), CCOLOR(BoldWhite) +}; + +#undef CCOLOR +#undef COPT + +static XtActionsRec action_table[] = +{ + {"XCursesButton", (XtActionProc)XCursesButton}, + {"XCursesKeyPress", (XtActionProc)XCursesKeyPress}, + {"XCursesPasteSelection", (XtActionProc)XCursesPasteSelection}, + {"string", (XtActionProc)XCursesHandleString} +}; + +static bool after_first_curses_request = FALSE; +static Pixel colors[MAX_COLORS + 2]; +static bool vertical_cursor = FALSE; + +#ifdef PDC_XIM +static XIM Xim = NULL; +static XIC Xic = NULL; +#endif + +static const char *default_translations = +{ + "<Key>: XCursesKeyPress() \n" \ + "<KeyUp>: XCursesKeyPress() \n" \ + "<BtnDown>: XCursesButton() \n" \ + "<BtnUp>: XCursesButton() \n" \ + "<BtnMotion>: XCursesButton()" +}; + +static int _to_utf8(char *outcode, chtype code) +{ +#ifdef PDC_WIDE + if (code & A_ALTCHARSET && !(code & 0xff80)) + code = acs_map[code & 0x7f]; +#endif + code &= A_CHARTEXT; + + if (code < 0x80) + { + outcode[0] = code; + return 1; + } + else + if (code < 0x800) + { + outcode[0] = ((code & 0x07c0) >> 6) | 0xc0; + outcode[1] = (code & 0x003f) | 0x80; + return 2; + } + else + { + outcode[0] = ((code & 0xf000) >> 12) | 0xe0; + outcode[1] = ((code & 0x0fc0) >> 6) | 0x80; + outcode[2] = (code & 0x003f) | 0x80; + return 3; + } +} + +static int _from_utf8(wchar_t *pwc, const char *s, size_t n) +{ + wchar_t key; + int i = -1; + const unsigned char *string; + + if (!s || (n < 1)) + return -1; + + if (!*s) + return 0; + + string = (const unsigned char *)s; + + key = string[0]; + + /* Simplistic UTF-8 decoder -- only does the BMP, minimal validation */ + + if (key & 0x80) + { + if ((key & 0xe0) == 0xc0) + { + if (1 < n) + { + key = ((key & 0x1f) << 6) | (string[1] & 0x3f); + i = 2; + } + } + else if ((key & 0xe0) == 0xe0) + { + if (2 < n) + { + key = ((key & 0x0f) << 12) | + ((string[1] & 0x3f) << 6) | (string[2] & 0x3f); + i = 3; + } + } + } + else + i = 1; + + if (i) + *pwc = key; + + return i; +} + +#ifndef X_HAVE_UTF8_STRING +static Atom XA_UTF8_STRING(Display *dpy) +{ + static AtomPtr p = NULL; + + if (!p) + p = XmuMakeAtom("UTF8_STRING"); + + return XmuInternAtom(dpy, p); +} +#endif + +signal_handler XCursesSetSignal(int signo, signal_handler action) +{ +#if defined(SA_INTERRUPT) || defined(SA_RESTART) + struct sigaction sigact, osigact; + + sigact.sa_handler = action; + + sigact.sa_flags = +# ifdef SA_INTERRUPT +# ifdef SA_RESTART + SA_INTERRUPT | SA_RESTART; +# else + SA_INTERRUPT; +# endif +# else /* must be SA_RESTART */ + SA_RESTART; +# endif + sigemptyset(&sigact.sa_mask); + + if (sigaction(signo, &sigact, &osigact)) + return SIG_ERR; + + return osigact.sa_handler; + +#else /* not SA_INTERRUPT or SA_RESTART, use plain signal */ + return signal(signo, action); +#endif +} + +RETSIGTYPE XCursesSigwinchHandler(int signo) +{ + PDC_LOG(("%s:XCursesSigwinchHandler() - called: SIGNO: %d\n", + XCLOGMSG, signo)); + + /* Patch by: Georg Fuchs, georg.fuchs@rz.uni-regensburg.de + 02-Feb-1999 */ + + SP->resized += 1; + + /* Always trap SIGWINCH if the C library supports SIGWINCH */ + +#ifdef SIGWINCH + XCursesSetSignal(SIGWINCH, XCursesSigwinchHandler); +#endif +} + +/* Convert character positions x and y to pixel positions, stored in + xpos and ypos */ + +static void _make_xy(int x, int y, int *xpos, int *ypos) +{ + *xpos = (x * font_width) + xc_app_data.borderWidth; + *ypos = xc_app_data.normalFont->ascent + (y * font_height) + + xc_app_data.borderWidth; +} + +/* Output a block of characters with common attributes */ + +static int _new_packet(chtype attr, bool rev, int len, int col, int row, +#ifdef PDC_WIDE + XChar2b *text) +#else + char *text) +#endif +{ + GC gc; + int xpos, ypos; + short fore, back; + + PDC_pair_content(PAIR_NUMBER(attr), &fore, &back); + +#ifdef PDC_WIDE + text[len].byte1 = text[len].byte2 = 0; +#else + text[len] = '\0'; +#endif + + /* Specify the color table offsets */ + + fore |= (attr & A_BOLD) ? 8 : 0; + back |= (attr & A_BLINK) ? 8 : 0; + + /* Reverse flag = highlighted selection XOR A_REVERSE set */ + + rev ^= !!(attr & A_REVERSE); + + /* Determine which GC to use - normal or italic */ + + gc = (attr & A_ITALIC) ? italic_gc : normal_gc; + + /* Draw it */ + + XSetForeground(XCURSESDISPLAY, gc, colors[rev ? back : fore]); + XSetBackground(XCURSESDISPLAY, gc, colors[rev ? fore : back]); + + _make_xy(col, row, &xpos, &ypos); + +#ifdef PDC_WIDE + XDrawImageString16( +#else + XDrawImageString( +#endif + XCURSESDISPLAY, XCURSESWIN, gc, xpos, ypos, text, len); + + /* Underline, etc. */ + + if (attr & (A_LEFTLINE|A_RIGHTLINE|A_UNDERLINE)) + { + int k; + + if (SP->line_color != -1) + XSetForeground(XCURSESDISPLAY, gc, colors[SP->line_color]); + + if (attr & A_UNDERLINE) /* UNDER */ + XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc, + xpos, ypos + 1, xpos + font_width * len, ypos + 1); + + if (attr & A_LEFTLINE) /* LEFT */ + for (k = 0; k < len; k++) + { + int x = xpos + font_width * k - 1; + XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc, + x, ypos - font_ascent, x, ypos + font_descent); + } + + if (attr & A_RIGHTLINE) /* RIGHT */ + for (k = 0; k < len; k++) + { + int x = xpos + font_width * (k + 1) - 1; + XDrawLine(XCURSESDISPLAY, XCURSESWIN, gc, + x, ypos - font_ascent, x, ypos + font_descent); + } + } + + PDC_LOG(("%s:_new_packet() - row: %d col: %d " + "num_cols: %d fore: %d back: %d text:<%s>\n", + XCLOGMSG, row, col, len, fore, back, text)); + + return OK; +} + +/* The core display routine -- update one line of text */ + +static int _display_text(const chtype *ch, int row, int col, + int num_cols, bool highlight) +{ +#ifdef PDC_WIDE + XChar2b text[513]; +#else + char text[513]; +#endif + chtype old_attr, attr; + int i, j; + + PDC_LOG(("%s:_display_text() - called: row: %d col: %d " + "num_cols: %d\n", XCLOGMSG, row, col, num_cols)); + + if (!num_cols) + return OK; + + old_attr = *ch & A_ATTRIBUTES; + + for (i = 0, j = 0; j < num_cols; j++) + { + chtype curr = ch[j]; + + attr = curr & A_ATTRIBUTES; + +#ifdef CHTYPE_LONG + if (attr & A_ALTCHARSET && !(curr & 0xff80)) + { + attr ^= A_ALTCHARSET; + curr = acs_map[curr & 0x7f]; + } +#endif + +#ifndef PDC_WIDE + /* Special handling for ACS_BLOCK */ + + if (!(curr & A_CHARTEXT)) + { + curr |= ' '; + attr ^= A_REVERSE; + } +#endif + if (attr != old_attr) + { + if (_new_packet(old_attr, highlight, i, col, row, text) == ERR) + return ERR; + + old_attr = attr; + col += i; + i = 0; + } + +#ifdef PDC_WIDE + text[i].byte1 = (curr & 0xff00) >> 8; + text[i++].byte2 = curr & 0x00ff; +#else + text[i++] = curr & 0xff; +#endif + } + + return _new_packet(old_attr, highlight, i, col, row, text); +} + +static void _get_gc(GC *gc, XFontStruct *font_info, int fore, int back) +{ + XGCValues values; + + /* Create default Graphics Context */ + + *gc = XCreateGC(XCURSESDISPLAY, XCURSESWIN, 0L, &values); + + /* specify font */ + + XSetFont(XCURSESDISPLAY, *gc, font_info->fid); + + XSetForeground(XCURSESDISPLAY, *gc, colors[fore]); + XSetBackground(XCURSESDISPLAY, *gc, colors[back]); +} + +static void _initialize_colors(void) +{ + colors[COLOR_BLACK] = xc_app_data.colorBlack; + colors[COLOR_RED] = xc_app_data.colorRed; + colors[COLOR_GREEN] = xc_app_data.colorGreen; + colors[COLOR_YELLOW] = xc_app_data.colorYellow; + colors[COLOR_BLUE] = xc_app_data.colorBlue; + colors[COLOR_MAGENTA] = xc_app_data.colorMagenta; + colors[COLOR_CYAN] = xc_app_data.colorCyan; + colors[COLOR_WHITE] = xc_app_data.colorWhite; + + colors[COLOR_BLACK + 8] = xc_app_data.colorBoldBlack; + colors[COLOR_RED + 8] = xc_app_data.colorBoldRed; + colors[COLOR_GREEN + 8] = xc_app_data.colorBoldGreen; + colors[COLOR_YELLOW + 8] = xc_app_data.colorBoldYellow; + colors[COLOR_BLUE + 8] = xc_app_data.colorBoldBlue; + colors[COLOR_MAGENTA + 8] = xc_app_data.colorBoldMagenta; + colors[COLOR_CYAN + 8] = xc_app_data.colorBoldCyan; + colors[COLOR_WHITE + 8] = xc_app_data.colorBoldWhite; + + colors[COLOR_CURSOR] = xc_app_data.cursorColor; + colors[COLOR_BORDER] = xc_app_data.borderColor; +} + +static void _refresh_scrollbar(void) +{ + XC_LOG(("_refresh_scrollbar() - called\n")); + + if (SP->sb_on) + { + PDC_SCROLLBAR_TYPE total_y = SP->sb_total_y; + PDC_SCROLLBAR_TYPE total_x = SP->sb_total_x; + + if (total_y) + XawScrollbarSetThumb(scrollVert, + (PDC_SCROLLBAR_TYPE)(SP->sb_cur_y) / total_y, + (PDC_SCROLLBAR_TYPE)(SP->sb_viewport_y) / total_y); + + if (total_x) + XawScrollbarSetThumb(scrollHoriz, + (PDC_SCROLLBAR_TYPE)(SP->sb_cur_x) / total_x, + (PDC_SCROLLBAR_TYPE)(SP->sb_viewport_x) / total_x); + } +} + +static void _set_cursor_color(chtype *ch, short *fore, short *back) +{ + int attr; + short f, b; + + attr = PAIR_NUMBER(*ch); + + if (attr) + { + PDC_pair_content(attr, &f, &b); + *fore = 7 - (f % 8); + *back = 7 - (b % 8); + } + else + { + if (*ch & A_REVERSE) + { + *back = COLOR_BLACK; + *fore = COLOR_WHITE; + } + else + { + *back = COLOR_WHITE; + *fore = COLOR_BLACK; + } + } +} + +static void _get_icon(void) +{ + XIconSize *icon_size; + int size_count = 0; + Status rc; + unsigned char *bitmap_bits = NULL; + unsigned icon_bitmap_width = 0, icon_bitmap_height = 0, + file_bitmap_width = 0, file_bitmap_height = 0; + + XC_LOG(("_get_icon() - called\n")); + + icon_size = XAllocIconSize(); + + rc = XGetIconSizes(XtDisplay(topLevel), + RootWindowOfScreen(XtScreen(topLevel)), + &icon_size, &size_count); + + /* if the WM can advise on icon sizes... */ + + if (rc && size_count) + { + int i, max_height = 0, max_width = 0; + + PDC_LOG(("%s:size_count: %d rc: %d\n", XCLOGMSG, size_count, rc)); + + for (i = 0; i < size_count; i++) + { + if (icon_size[i].max_width > max_width) + max_width = icon_size[i].max_width; + if (icon_size[i].max_height > max_height) + max_height = icon_size[i].max_height; + + PDC_LOG(("%s:min: %d %d\n", XCLOGMSG, + icon_size[i].min_width, icon_size[i].min_height)); + + PDC_LOG(("%s:max: %d %d\n", XCLOGMSG, + icon_size[i].max_width, icon_size[i].max_height)); + + PDC_LOG(("%s:inc: %d %d\n", XCLOGMSG, + icon_size[i].width_inc, icon_size[i].height_inc)); + } + + if (max_width >= big_icon_width && max_height >= big_icon_height) + { + icon_bitmap_width = big_icon_width; + icon_bitmap_height = big_icon_height; + bitmap_bits = (unsigned char *)big_icon_bits; + } + else + { + icon_bitmap_width = little_icon_width; + icon_bitmap_height = little_icon_height; + bitmap_bits = (unsigned char *)little_icon_bits; + } + + } + else /* use small icon */ + { + icon_bitmap_width = little_icon_width; + icon_bitmap_height = little_icon_height; + bitmap_bits = (unsigned char *)little_icon_bits; + } + + XFree(icon_size); + +#ifdef HAVE_XPM_H + if (xc_app_data.pixmap && xc_app_data.pixmap[0]) /* supplied pixmap */ + { + XpmReadFileToPixmap(XtDisplay(topLevel), + RootWindowOfScreen(XtScreen(topLevel)), + (char *)xc_app_data.pixmap, + &icon_pixmap, &icon_pixmap_mask, NULL); + return; + } +#endif + + if (xc_app_data.bitmap && xc_app_data.bitmap[0]) /* supplied bitmap */ + { + int x_hot = 0, y_hot = 0; + + rc = XReadBitmapFile(XtDisplay(topLevel), + RootWindowOfScreen(XtScreen(topLevel)), + (char *)xc_app_data.bitmap, + &file_bitmap_width, &file_bitmap_height, + &icon_bitmap, &x_hot, &y_hot); + + switch(rc) + { + case BitmapOpenFailed: + fprintf(stderr, "bitmap file %s: not found\n", + xc_app_data.bitmap); + break; + case BitmapFileInvalid: + fprintf(stderr, "bitmap file %s: contents invalid\n", + xc_app_data.bitmap); + break; + default: + return; + } + } + + icon_bitmap = XCreateBitmapFromData(XtDisplay(topLevel), + RootWindowOfScreen(XtScreen(topLevel)), + (char *)bitmap_bits, icon_bitmap_width, icon_bitmap_height); +} + +static void _draw_border(void) +{ + /* Draw the border if required */ + + if (xc_app_data.borderWidth) + XDrawRectangle(XCURSESDISPLAY, XCURSESWIN, border_gc, + xc_app_data.borderWidth / 2, + xc_app_data.borderWidth / 2, + window_width - xc_app_data.borderWidth, + window_height - xc_app_data.borderWidth); +} + +/* Redraw the entire screen */ + +static void _display_screen(void) +{ + int row; + + XC_LOG(("_display_screen() - called\n")); + + for (row = 0; row < XCursesLINES; row++) + { + XC_get_line_lock(row); + + _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row)), + row, 0, COLS, FALSE); + + XC_release_line_lock(row); + } + + _redraw_cursor(); + _draw_border(); +} + +/* Draw changed portions of the screen */ + +static void _refresh_screen(void) +{ + int row, start_col, num_cols; + + XC_LOG(("_refresh_screen() - called\n")); + + for (row = 0; row < XCursesLINES; row++) + { + num_cols = (int)*(Xcurscr + XCURSCR_LENGTH_OFF + row); + + if (num_cols) + { + XC_get_line_lock(row); + + start_col = (int)*(Xcurscr + XCURSCR_START_OFF + row); + + _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row) + + (start_col * sizeof(chtype))), row, start_col, + num_cols, FALSE); + + *(Xcurscr + XCURSCR_LENGTH_OFF + row) = 0; + + XC_release_line_lock(row); + } + } + + if (mouse_selection) + _selection_off(); +} + +static void _handle_expose(Widget w, XtPointer client_data, XEvent *event, + Boolean *unused) +{ + XC_LOG(("_handle_expose() - called\n")); + + /* ignore all Exposes except last */ + + if (event->xexpose.count) + return; + + if (after_first_curses_request && received_map_notify) + _display_screen(); +} + +static void _handle_nonmaskable(Widget w, XtPointer client_data, XEvent *event, + Boolean *unused) +{ + XClientMessageEvent *client_event = (XClientMessageEvent *)event; + + PDC_LOG(("%s:_handle_nonmaskable called: xc_otherpid %d event %d\n", + XCLOGMSG, xc_otherpid, event->type)); + + if (event->type == ClientMessage) + { + XC_LOG(("ClientMessage received\n")); + + /* This code used to include handling of WM_SAVE_YOURSELF, but + it resulted in continual failure of THE on my Toshiba laptop. + Removed on 3-3-2001. Now only exits on WM_DELETE_WINDOW. */ + + if ((Atom)client_event->data.s[0] == wm_atom[0]) + _exit_process(0, SIGKILL, ""); + } +} + +static void XCursesKeyPress(Widget w, XEvent *event, String *params, + Cardinal *nparams) +{ + enum { STATE_NORMAL, STATE_COMPOSE, STATE_CHAR }; + +#ifdef PDC_XIM + Status status; + wchar_t buffer[120]; +#else + unsigned char buffer[120]; + XComposeStatus compose; + static int compose_state = STATE_NORMAL; + static int compose_index = 0; + int char_idx = 0; +#endif + unsigned long key = 0; + int buflen = 40; + int i, count; + unsigned long modifier = 0; + bool key_code = FALSE; + + XC_LOG(("XCursesKeyPress() - called\n")); + + /* Handle modifier keys first; ignore other KeyReleases */ + + if (event->type == KeyRelease) + { + /* The keysym value was set by a previous call to this function + with a KeyPress event (or reset by the mouse event handler) */ + + if (SP->return_key_modifiers && +#ifndef PDC_XIM + keysym != compose_key && +#endif + IsModifierKey(keysym)) + { + switch (keysym) { + case XK_Shift_L: + key = KEY_SHIFT_L; + break; + case XK_Shift_R: + key = KEY_SHIFT_R; + break; + case XK_Control_L: + key = KEY_CONTROL_L; + break; + case XK_Control_R: + key = KEY_CONTROL_R; + break; + case XK_Alt_L: + key = KEY_ALT_L; + break; + case XK_Alt_R: + key = KEY_ALT_R; + } + + if (key) + _send_key_to_curses(key, NULL, TRUE); + } + + return; + } + + buffer[0] = '\0'; + +#ifdef PDC_XIM + count = XwcLookupString(Xic, &(event->xkey), buffer, buflen, + &keysym, &status); +#else + count = XLookupString(&(event->xkey), (char *)buffer, buflen, + &keysym, &compose); +#endif + + /* translate keysym into curses key code */ + + PDC_LOG(("%s:Key mask: %x\n", XCLOGMSG, event->xkey.state)); + +#ifdef PDCDEBUG + for (i = 0; i < 4; i++) + PDC_debug("%s:Keysym %x %d\n", XCLOGMSG, + XKeycodeToKeysym(XCURSESDISPLAY, event->xkey.keycode, i), i); +#endif + +#ifndef PDC_XIM + + /* Check if the key just pressed is the user-specified compose + key; if it is, set the compose state and exit. */ + + if (keysym == compose_key) + { + chtype *ch; + int xpos, ypos, save_visibility = SP->visibility; + short fore = 0, back = 0; + + /* Change the shape of the cursor to an outline rectangle to + indicate we are in "compose" status */ + + SP->visibility = 0; + + _redraw_cursor(); + + SP->visibility = save_visibility; + _make_xy(SP->curscol, SP->cursrow, &xpos, &ypos); + + ch = (chtype *)(Xcurscr + XCURSCR_Y_OFF(SP->cursrow) + + (SP->curscol * sizeof(chtype))); + + _set_cursor_color(ch, &fore, &back); + + XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]); + + XDrawRectangle(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc, + xpos + 1, ypos - font_height + + xc_app_data.normalFont->descent + 1, + font_width - 2, font_height - 2); + + compose_state = STATE_COMPOSE; + return; + } + + switch (compose_state) + { + case STATE_COMPOSE: + if (IsModifierKey(keysym)) + return; + + if (event->xkey.state & compose_mask) + { + compose_state = STATE_NORMAL; + _redraw_cursor(); + break; + } + + if (buffer[0] && count == 1) + key = buffer[0]; + + compose_index = -1; + + for (i = 0; i < (int)strlen(compose_chars); i++) + if (compose_chars[i] == key) + { + compose_index = i; + break; + } + + if (compose_index == -1) + { + compose_state = STATE_NORMAL; + compose_index = 0; + _redraw_cursor(); + break; + } + + compose_state = STATE_CHAR; + return; + + case STATE_CHAR: + if (IsModifierKey(keysym)) + return; + + if (event->xkey.state & compose_mask) + { + compose_state = STATE_NORMAL; + _redraw_cursor(); + break; + } + + if (buffer[0] && count == 1) + key = buffer[0]; + + char_idx = -1; + + for (i = 0; i < MAX_COMPOSE_CHARS; i++) + if (compose_lookups[compose_index][i] == key) + { + char_idx = i; + break; + } + + if (char_idx == -1) + { + compose_state = STATE_NORMAL; + compose_index = 0; + _redraw_cursor(); + break; + } + + _send_key_to_curses(compose_keys[compose_index][char_idx], + NULL, FALSE); + + compose_state = STATE_NORMAL; + compose_index = 0; + + _redraw_cursor(); + + return; + } + +#endif /* PDC_XIM */ + + /* To get here we are procesing "normal" keys */ + + PDC_LOG(("%s:Keysym %x %d\n", XCLOGMSG, + XKeycodeToKeysym(XCURSESDISPLAY, event->xkey.keycode, key), key)); + + if (SP->save_key_modifiers) + { + /* 0x10: usually, numlock modifier */ + + if (event->xkey.state & Mod2Mask) + modifier |= PDC_KEY_MODIFIER_NUMLOCK; + + /* 0x01: shift modifier */ + + if (event->xkey.state & ShiftMask) + modifier |= PDC_KEY_MODIFIER_SHIFT; + + /* 0x04: control modifier */ + + if (event->xkey.state & ControlMask) + modifier |= PDC_KEY_MODIFIER_CONTROL; + + /* 0x08: usually, alt modifier */ + + if (event->xkey.state & Mod1Mask) + modifier |= PDC_KEY_MODIFIER_ALT; + } + + for (i = 0; key_table[i].keycode; i++) + { + if (key_table[i].keycode == keysym) + { + PDC_LOG(("%s:State %x\n", XCLOGMSG, event->xkey.state)); + + /* ControlMask: 0x04: control modifier + Mod1Mask: 0x08: usually, alt modifier + Mod2Mask: 0x10: usually, numlock modifier + ShiftMask: 0x01: shift modifier */ + + if ((event->xkey.state & ShiftMask) || + (key_table[i].numkeypad && + (event->xkey.state & Mod2Mask))) + { + key = key_table[i].shifted; + } + else if (event->xkey.state & ControlMask) + { + key = key_table[i].control; + } + else if (event->xkey.state & Mod1Mask) + { + key = key_table[i].alt; + } + + /* To get here, we ignore all other modifiers */ + + else + key = key_table[i].normal; + + key_code = (key > 0x100); + break; + } + } + + if (!key && buffer[0] && count == 1) + key = buffer[0]; + + PDC_LOG(("%s:Key: %s pressed - %x Mod: %x\n", XCLOGMSG, + XKeysymToString(keysym), key, event->xkey.state)); + + /* Handle ALT letters and numbers */ + + if (event->xkey.state == Mod1Mask) + { + if (key >= 'A' && key <= 'Z') + { + key += ALT_A - 'A'; + key_code = TRUE; + } + + if (key >= 'a' && key <= 'z') + { + key += ALT_A - 'a'; + key_code = TRUE; + } + + if (key >= '0' && key <= '9') + { + key += ALT_0 - '0'; + key_code = TRUE; + } + } + + /* After all that, send the key back to the application if is + NOT zero. */ + + if (key) + { + key |= (modifier << 24); + + _send_key_to_curses(key, NULL, key_code); + } +} + +static void XCursesHandleString(Widget w, XEvent *event, String *params, + Cardinal *nparams) +{ + unsigned char *ptr; + + if (*nparams != 1) + return; + + ptr = (unsigned char *)*params; + + if (ptr[0] == '0' && ptr[1] == 'x' && ptr[2] != '\0') + { + unsigned char c; + unsigned long total = 0; + + for (ptr += 2; (c = tolower(*ptr)); ptr++) + { + total <<= 4; + + if (c >= '0' && c <= '9') + total += c - '0'; + else + if (c >= 'a' && c <= 'f') + total += c - ('a' - 10); + else + break; + } + + if (c == '\0') + _send_key_to_curses(total, NULL, FALSE); + } + else + for (; *ptr; ptr++) + _send_key_to_curses((unsigned long)*ptr, NULL, FALSE); +} + +static void _paste_string(Widget w, XtPointer data, Atom *selection, Atom *type, + XtPointer value, unsigned long *length, int *format) +{ + unsigned long i, key; + unsigned char *string = value; + + XC_LOG(("_paste_string() - called\n")); + + if (!*type || !*length || !string) + return; + + for (i = 0; string[i] && (i < (*length)); i++) + { + key = string[i]; + + if (key == 10) /* new line - convert to ^M */ + key = 13; + + _send_key_to_curses(key, NULL, FALSE); + } + + XtFree(value); +} + +static void _paste_utf8(Widget w, XtPointer event, Atom *selection, Atom *type, + XtPointer value, unsigned long *length, int *format) +{ + wchar_t key; + size_t i = 0, len; + char *string = value; + + XC_LOG(("_paste_utf8() - called\n")); + + if (!*type || !*length) + { + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _paste_string, + event, ((XButtonEvent *)event)->time); + return; + } + + len = *length; + + if (!string) + return; + + while (string[i] && (i < len)) + { + int retval = _from_utf8(&key, string + i, len - i); + + if (retval < 1) + return; + + if (key == 10) /* new line - convert to ^M */ + key = 13; + + _send_key_to_curses(key, NULL, FALSE); + + i += retval; + } + + XtFree(value); +} + +static void XCursesPasteSelection(Widget w, XButtonEvent *button_event) +{ + XC_LOG(("XCursesPasteSelection() - called\n")); + + XtGetSelectionValue(w, XA_PRIMARY, XA_UTF8_STRING(XtDisplay(w)), + _paste_utf8, (XtPointer)button_event, + button_event->time); +} + +static Boolean _convert_proc(Widget w, Atom *selection, Atom *target, + Atom *type_return, XtPointer *value_return, + unsigned long *length_return, int *format_return) +{ + XC_LOG(("_convert_proc() - called\n")); + + if (*target == XA_TARGETS(XtDisplay(topLevel))) + { + XSelectionRequestEvent *req = XtGetSelectionRequest(w, + *selection, (XtRequestId)NULL); + + Atom *targetP; + XPointer std_targets; + unsigned long std_length; + + XmuConvertStandardSelection(topLevel, req->time, selection, + target, type_return, &std_targets, + &std_length, format_return); + + *length_return = std_length + 2; + *value_return = XtMalloc(sizeof(Atom) * (*length_return)); + + targetP = *(Atom**)value_return; + *targetP++ = XA_STRING; + *targetP++ = XA_UTF8_STRING(XtDisplay(topLevel)); + + memmove((void *)targetP, (const void *)std_targets, + sizeof(Atom) * std_length); + + XtFree((char *)std_targets); + *type_return = XA_ATOM; + *format_return = sizeof(Atom) * 8; + + return True; + } + else if (*target == XA_UTF8_STRING(XtDisplay(topLevel)) || + *target == XA_STRING) + { + bool utf8 = !(*target == XA_STRING); + char *data = XtMalloc(tmpsel_length * 3 + 1); + chtype *tmp = tmpsel; + int ret_length = 0; + + if (utf8) + { + while (*tmp) + ret_length += _to_utf8(data + ret_length, *tmp++); + } + else + while (*tmp) + data[ret_length++] = *tmp++ & 0xff; + + data[ret_length++] = '\0'; + + *value_return = data; + *length_return = ret_length; + *format_return = 8; + *type_return = *target; + + return True; + } + else + return XmuConvertStandardSelection(topLevel, CurrentTime, + selection, target, type_return, (XPointer*)value_return, + length_return, format_return); +} + +static void _lose_ownership(Widget w, Atom *type) +{ + XC_LOG(("_lose_ownership() - called\n")); + + if (tmpsel) + free(tmpsel); + + tmpsel = NULL; + tmpsel_length = 0; + _selection_off(); +} + +static void _show_selection(int start_x, int start_y, int end_x, int end_y, + bool highlight) +{ + int i, num_cols, start_col, row; + + PDC_LOG(("%s:_show_selection() - called StartX: %d StartY: %d " + "EndX: %d EndY: %d Highlight: %d\n", XCLOGMSG, + start_x, start_y, end_x, end_y, highlight)); + + for (i = 0; i < end_y - start_y + 1; i++) + { + if (start_y == end_y) /* only one line */ + { + start_col = start_x; + num_cols = end_x - start_x + 1; + row = start_y; + } + else if (!i) /* first line */ + { + start_col = start_x; + num_cols = COLS - start_x; + row = start_y; + } + else if (start_y + i == end_y) /* last line */ + { + start_col = 0; + num_cols = end_x + 1; + row = end_y; + } + else /* full line */ + { + start_col = 0; + num_cols = COLS; + row = start_y + i; + } + + XC_get_line_lock(row); + + _display_text((const chtype *)(Xcurscr + XCURSCR_Y_OFF(row) + + (start_col * sizeof(chtype))), row, start_col, + num_cols, highlight); + + XC_release_line_lock(row); + } +} + +static void _selection_off(void) +{ + XC_LOG(("_selection_off() - called\n")); + + _display_screen(); + + selection_start_x = selection_start_y = selection_end_x = + selection_end_y = 0; + + mouse_selection = FALSE; +} + +static void _selection_on(int x, int y) +{ + XC_LOG(("_selection_on() - called\n")); + + selection_start_x = selection_end_x = x; + selection_start_y = selection_end_y = y; +} + +static void _selection_extend(int x, int y) +{ + int temp, current_start, current_end, current_start_x, + current_end_x, current_start_y, current_end_y, new_start, + new_end, new_start_x, new_end_x, new_start_y, new_end_y; + + XC_LOG(("_selection_extend() - called\n")); + + mouse_selection = TRUE; + + /* convert x/y coordinates into start/stop */ + + current_start = (selection_start_y * COLS) + selection_start_x; + current_end = (selection_end_y * COLS) + selection_end_x; + + if (current_start > current_end) + { + current_start_x = selection_end_x; + current_start_y = selection_end_y; + current_end_x = selection_start_x; + current_end_y = selection_start_y; + temp = current_start; + current_start = current_end; + current_end = temp; + } + else + { + current_end_x = selection_end_x; + current_end_y = selection_end_y; + current_start_x = selection_start_x; + current_start_y = selection_start_y; + } + + /* Now we have the current selection as a linear expression. + Convert the new position to a linear expression. */ + + selection_end_x = x; + selection_end_y = y; + + /* convert x/y coordinates into start/stop */ + + new_start = (selection_start_y * COLS) + selection_start_x; + new_end = (selection_end_y * COLS) + selection_end_x; + + if (new_start > new_end) + { + new_start_x = selection_end_x; + new_start_y = selection_end_y; + new_end_x = selection_start_x; + new_end_y = selection_start_y; + temp = new_start; + new_start = new_end; + new_end = temp; + } + else + { + new_end_x = selection_end_x; + new_end_y = selection_end_y; + new_start_x = selection_start_x; + new_start_y = selection_start_y; + } + + if (new_end > current_end) + _show_selection(current_end_x, current_end_y, new_end_x, + new_end_y, TRUE); + else if (new_end < current_end) + _show_selection(new_end_x, new_end_y, current_end_x, + current_end_y, FALSE); + else if (new_start < current_start) + _show_selection(new_start_x, new_start_y, current_start_x, + current_start_y, TRUE); + else if (new_start > current_start) + _show_selection(current_start_x, current_start_y, + new_start_x, new_start_y, FALSE); + else + _show_selection(current_start_x, current_start_y, + new_start_x, new_start_y, TRUE); +} + +static void _selection_set(void) +{ + int i, j, start, end, start_x, end_x, start_y, end_y, num_cols, + start_col, row, num_chars, ch, last_nonblank, length, newlen; + chtype *ptr = NULL; + + XC_LOG(("_selection_set() - called\n")); + + /* convert x/y coordinates into start/stop */ + + start = (selection_start_y * COLS) + selection_start_x; + end = (selection_end_y * COLS) + selection_end_x; + + if (start == end) + { + if (tmpsel) + free(tmpsel); + + tmpsel = NULL; + tmpsel_length = 0; + + return; + } + + if (start > end) + { + start_x = selection_end_x; + start_y = selection_end_y; + end_x = selection_start_x; + end_y = selection_start_y; + length = start - end + 1; + } + else + { + end_x = selection_end_x; + end_y = selection_end_y; + start_x = selection_start_x; + start_y = selection_start_y; + length = end - start + 1; + } + + newlen = length + end_y - start_y + 2; + + if (length > (int)tmpsel_length) + { + if (!tmpsel_length) + tmpsel = malloc(newlen * sizeof(chtype)); + else + tmpsel = realloc(tmpsel, newlen * sizeof(chtype)); + } + + if (!tmpsel) + { + tmpsel_length = 0; + return; + } + + tmpsel_length = length; + num_chars = 0; + + for (i = 0; i < end_y - start_y + 1; i++) + { + + if (start_y == end_y) /* only one line */ + { + start_col = start_x; + num_cols = end_x - start_x + 1; + row = start_y; + } + else if (!i) /* first line */ + { + start_col = start_x; + num_cols = COLS - start_x; + row = start_y; + } + else if (start_y + i == end_y) /* last line */ + { + start_col = 0; + num_cols = end_x + 1; + row = end_y; + } + else /* full line */ + { + start_col = 0; + num_cols = COLS; + row = start_y + i; + } + + XC_get_line_lock(row); + + ptr = (chtype *)(Xcurscr + XCURSCR_Y_OFF(row) + + start_col * sizeof(chtype)); + + if (i < end_y - start_y) + { + last_nonblank = 0; + + for (j = 0; j < num_cols; j++) + { + ch = (int)(ptr[j] & A_CHARTEXT); + if (ch != (int)' ') + last_nonblank = j; + } + } + else + last_nonblank = num_cols - 1; + + for (j = 0; j <= last_nonblank; j++) + tmpsel[num_chars++] = ptr[j]; + + XC_release_line_lock(row); + + if (i < end_y - start_y) + tmpsel[num_chars++] = '\n'; + } + + tmpsel[num_chars] = '\0'; + tmpsel_length = num_chars; +} + +static void _display_cursor(int old_row, int old_x, int new_row, int new_x) +{ + int xpos, ypos, i; + chtype *ch; + short fore = 0, back = 0; + + PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n", + XCLOGMSG, old_row, old_x)); + + /* if the cursor position is outside the boundary of the screen, + ignore the request */ + + if (old_row >= XCursesLINES || old_x >= COLS || + new_row >= XCursesLINES || new_x >= COLS) + return; + + /* display the character at the current cursor position */ + + PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n", + XCLOGMSG, old_row, old_x)); + + _display_text((const chtype *)(Xcurscr + (XCURSCR_Y_OFF(old_row) + + (old_x * sizeof(chtype)))), old_row, old_x, 1, FALSE); + + /* display the cursor at the new cursor position */ + + if (!SP->visibility) + return; /* cursor not displayed, no more to do */ + + _make_xy(new_x, new_row, &xpos, &ypos); + + ch = (chtype *)(Xcurscr + XCURSCR_Y_OFF(new_row) + new_x * sizeof(chtype)); + + _set_cursor_color(ch, &fore, &back); + + if (vertical_cursor) + { + XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]); + + for (i = 1; i <= SP->visibility; i++) + XDrawLine(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc, + xpos + i, ypos - xc_app_data.normalFont->ascent, + xpos + i, ypos - xc_app_data.normalFont->ascent + + font_height - 1); + } + else + { + if (SP->visibility == 1) + { + /* cursor visibility normal */ + + XSetForeground(XCURSESDISPLAY, rect_cursor_gc, colors[back]); + + for (i = 0; i < xc_app_data.normalFont->descent + 2; i++) + XDrawLine(XCURSESDISPLAY, XCURSESWIN, rect_cursor_gc, + xpos, ypos - 2 + i, xpos + font_width, ypos - 2 + i); + } + else + { + /* cursor visibility high */ +#ifdef PDC_WIDE + XChar2b buf[2]; + + buf[0].byte1 = (*ch & 0xff00) >> 8; + buf[0].byte2 = *ch & 0x00ff; + + buf[1].byte1 = buf[1].byte2 = 0; +#else + char buf[2]; + + buf[0] = *ch & 0xff; + buf[1] = '\0'; +#endif + XSetForeground(XCURSESDISPLAY, block_cursor_gc, colors[fore]); + XSetBackground(XCURSESDISPLAY, block_cursor_gc, colors[back]); +#ifdef PDC_WIDE + XDrawImageString16( +#else + XDrawImageString( +#endif + XCURSESDISPLAY, XCURSESWIN, block_cursor_gc, + xpos, ypos, buf, 1); + } + } + + PDC_LOG(("%s:_display_cursor() - draw cursor at row %d col %d\n", + XCLOGMSG, new_row, new_x)); +} + +static void _redraw_cursor(void) +{ + _display_cursor(SP->cursrow, SP->curscol, SP->cursrow, SP->curscol); +} + +static void _handle_enter_leave(Widget w, XtPointer client_data, + XEvent *event, Boolean *unused) +{ + XC_LOG(("_handle_enter_leave called\n")); + + switch(event->type) + { + case EnterNotify: + XC_LOG(("EnterNotify received\n")); + + window_entered = TRUE; + break; + + case LeaveNotify: + XC_LOG(("LeaveNotify received\n")); + + window_entered = FALSE; + + /* Display the cursor so it stays on while the window is + not current */ + + _redraw_cursor(); + break; + + default: + PDC_LOG(("%s:_handle_enter_leave - unknown event %d\n", + XCLOGMSG, event->type)); + } +} + +static void _send_key_to_curses(unsigned long key, MOUSE_STATUS *ms, + bool key_code) +{ + PDC_LOG(("%s:_send_key_to_curses() - called: sending %d\n", + XCLOGMSG, key)); + + SP->key_code = key_code; + + if (XC_write_socket(xc_key_sock, &key, sizeof(unsigned long)) < 0) + _exit_process(1, SIGKILL, "exiting from _send_key_to_curses"); + + if (ms) + { + MOUSE_LOG(("%s:writing mouse stuff\n", XCLOGMSG)); + + if (XC_write_socket(xc_key_sock, ms, sizeof(MOUSE_STATUS)) < 0) + _exit_process(1, SIGKILL, "exiting from _send_key_to_curses"); + } +} + +static void _blink_cursor(XtPointer unused, XtIntervalId *id) +{ + XC_LOG(("_blink_cursor() - called:\n")); + + if (window_entered) + { + if (visible_cursor) + { + /* Cursor currently ON, turn it off */ + + int save_visibility = SP->visibility; + SP->visibility = 0; + _redraw_cursor(); + SP->visibility = save_visibility; + visible_cursor = FALSE; + } + else + { + /* Cursor currently OFF, turn it on */ + + _redraw_cursor(); + visible_cursor = TRUE; + } + } + + XtAppAddTimeOut(app_context, xc_app_data.cursorBlinkRate, + _blink_cursor, NULL); +} + +static void XCursesButton(Widget w, XEvent *event, String *params, + Cardinal *nparams) +{ + int button_no; + static int last_button_no = 0; + static Time last_button_press_time = 0; + MOUSE_STATUS save_mouse_status; + bool send_key = TRUE; + static bool remove_release; + static bool handle_real_release; + + XC_LOG(("XCursesButton() - called\n")); + + keysym = 0; /* suppress any modifier key return */ + + save_mouse_status = Mouse_status; + button_no = event->xbutton.button; + + /* It appears that under X11R6 (at least on Linux), that an + event_type of ButtonMotion does not include the mouse button in + the event. The following code is designed to cater for this + situation. */ + + if (!button_no) + button_no = last_button_no; + + last_button_no = button_no; + + Mouse_status.changes = 0; + + switch(event->type) + { + case ButtonPress: + /* Handle button 4 and 5, which are normally mapped to the wheel + mouse scroll up and down */ + + if (button_no == 4 || button_no == 5) + { + /* Send the KEY_MOUSE to curses program */ + + memset(&Mouse_status, 0, sizeof(Mouse_status)); + + Mouse_status.changes = (button_no == 5) ? + PDC_MOUSE_WHEEL_DOWN : PDC_MOUSE_WHEEL_UP; + + MOUSE_X_POS = MOUSE_Y_POS = -1; + _send_key_to_curses(KEY_MOUSE, &Mouse_status, TRUE); + remove_release = TRUE; + + return; + } + + if (button_no == 2 && + (!SP->_trap_mbe || (event->xbutton.state & ShiftMask))) + { + XCursesPasteSelection(drawing, (XButtonEvent *)event); + remove_release = TRUE; + + return; + } + + remove_release = False; + handle_real_release = False; + + MOUSE_LOG(("\nButtonPress\n")); + + if ((event->xbutton.time - last_button_press_time) < + xc_app_data.doubleClickPeriod) + { + MOUSE_X_POS = save_mouse_status.x; + MOUSE_Y_POS = save_mouse_status.y; + BUTTON_STATUS(button_no) = BUTTON_DOUBLE_CLICKED; + + _selection_off(); + remove_release = True; + } + else + { + napms(SP->mouse_wait); + event->type = ButtonRelease; + XSendEvent(event->xbutton.display, event->xbutton.window, + True, 0, event); + last_button_press_time = event->xbutton.time; + + return; + } + + last_button_press_time = event->xbutton.time; + break; + + case MotionNotify: + MOUSE_LOG(("\nMotionNotify: y: %d x: %d Width: %d " + "Height: %d\n", event->xbutton.y, event->xbutton.x, + font_width, font_height)); + + MOUSE_X_POS = (event->xbutton.x - xc_app_data.borderWidth) / + font_width; + MOUSE_Y_POS = (event->xbutton.y - xc_app_data.borderWidth) / + font_height; + + if (button_no == 1 && + (!SP->_trap_mbe || (event->xbutton.state & ShiftMask))) + { + _selection_extend(MOUSE_X_POS, MOUSE_Y_POS); + send_key = FALSE; + } + else + _selection_off(); + + /* Throw away mouse movements if they are in the same character + position as the last mouse event, or if we are currently in + the middle of a double click event. */ + + if ((MOUSE_X_POS == save_mouse_status.x && + MOUSE_Y_POS == save_mouse_status.y) || + save_mouse_status.button[button_no - 1] == BUTTON_DOUBLE_CLICKED) + { + send_key = FALSE; + break; + } + + Mouse_status.changes |= PDC_MOUSE_MOVED; + break; + + case ButtonRelease: + if (remove_release) + { + MOUSE_LOG(("Release at: %ld - removed\n", event->xbutton.time)); + return; + } + else + { + MOUSE_X_POS = (event->xbutton.x - xc_app_data.borderWidth) / + font_width; + MOUSE_Y_POS = (event->xbutton.y - xc_app_data.borderWidth) / + font_height; + + if (!handle_real_release) + { + if ((event->xbutton.time - last_button_press_time) < + SP->mouse_wait && + (event->xbutton.time != last_button_press_time)) + { + /* The "real" release was shorter than usleep() time; + therefore generate a click event */ + + MOUSE_LOG(("Release at: %ld - click\n", + event->xbutton.time)); + + BUTTON_STATUS(button_no) = BUTTON_CLICKED; + + if (button_no == 1 && mouse_selection && + (!SP->_trap_mbe || (event->xbutton.state & ShiftMask))) + { + send_key = FALSE; + + if (XtOwnSelection(topLevel, XA_PRIMARY, + event->xbutton.time, _convert_proc, + _lose_ownership, NULL) == False) + _selection_off(); + } + else + _selection_off(); + + /* Ensure the "pseudo" release event is ignored */ + + remove_release = True; + handle_real_release = False; + break; + } + else + { + /* Button release longer than usleep() time; + therefore generate a press and wait for the real + release to occur later. */ + + MOUSE_LOG(("Generated Release at: %ld - " + "press & release\n", event->xbutton.time)); + + BUTTON_STATUS(button_no) = BUTTON_PRESSED; + + if (button_no == 1 && + (!SP->_trap_mbe || (event->xbutton.state & ShiftMask))) + { + _selection_off(); + _selection_on(MOUSE_X_POS, MOUSE_Y_POS); + } + + handle_real_release = True; + break; + } + } + else + { + MOUSE_LOG(("Release at: %ld - released\n", + event->xbutton.time)); + } + } + + MOUSE_LOG(("\nButtonRelease\n")); + + BUTTON_STATUS(button_no) = BUTTON_RELEASED; + + if (button_no == 1 && mouse_selection && + (!SP->_trap_mbe || (event->xbutton.state & ShiftMask))) + { + send_key = FALSE; + + if (XtOwnSelection(topLevel, XA_PRIMARY, + event->xbutton.time, _convert_proc, + _lose_ownership, NULL) == False) + _selection_off(); + + _selection_set(); + } + else + _selection_off(); + + break; + } + + /* Set up the mouse status fields in preparation for sending */ + + Mouse_status.changes |= 1 << (button_no - 1); + + if (Mouse_status.changes & PDC_MOUSE_MOVED && + BUTTON_STATUS(button_no) == BUTTON_PRESSED) + BUTTON_STATUS(button_no) = BUTTON_MOVED; + + if (event->xbutton.state & ShiftMask) + BUTTON_STATUS(button_no) |= BUTTON_SHIFT; + if (event->xbutton.state & ControlMask) + BUTTON_STATUS(button_no) |= BUTTON_CONTROL; + if (event->xbutton.state & Mod1Mask) + BUTTON_STATUS(button_no) |= BUTTON_ALT; + + /* If we are ignoring the event, or the mouse position is outside + the bounds of the screen (because of the border), return here */ + + MOUSE_LOG(("Button: %d x: %d y: %d Button status: %x " + "Mouse status: %x\n", button_no, MOUSE_X_POS, MOUSE_Y_POS, + BUTTON_STATUS(button_no), Mouse_status.changes)); + + MOUSE_LOG(("Send: %d Button1: %x Button2: %x Button3: %x %d %d\n", + send_key, BUTTON_STATUS(1), BUTTON_STATUS(2), + BUTTON_STATUS(3), XCursesLINES, XCursesCOLS)); + + if (!send_key || MOUSE_X_POS < 0 || MOUSE_X_POS >= XCursesCOLS || + MOUSE_Y_POS < 0 || MOUSE_Y_POS >= XCursesLINES) + return; + + /* Send the KEY_MOUSE to curses program */ + + _send_key_to_curses(KEY_MOUSE, &Mouse_status, TRUE); +} + +static void _scroll_up_down(Widget w, XtPointer client_data, + XtPointer call_data) +{ + int pixels = (long) call_data; + int total_y = SP->sb_total_y * font_height; + int viewport_y = SP->sb_viewport_y * font_height; + int cur_y = SP->sb_cur_y * font_height; + + /* When pixels is negative, right button pressed, move data down, + thumb moves up. Otherwise, left button pressed, pixels positive, + move data up, thumb down. */ + + cur_y += pixels; + + /* limit panning to size of overall */ + + if (cur_y < 0) + cur_y = 0; + else + if (cur_y > (total_y - viewport_y)) + cur_y = total_y - viewport_y; + + SP->sb_cur_y = cur_y / font_height; + + XawScrollbarSetThumb(w, (double)((double)cur_y / (double)total_y), + (double)((double)viewport_y / (double)total_y)); + + /* Send a key: if pixels negative, send KEY_SCROLL_DOWN */ + + _send_key_to_curses(KEY_SF, NULL, TRUE); +} + +static void _scroll_left_right(Widget w, XtPointer client_data, + XtPointer call_data) +{ + int pixels = (long) call_data; + int total_x = SP->sb_total_x * font_width; + int viewport_x = SP->sb_viewport_x * font_width; + int cur_x = SP->sb_cur_x * font_width; + + cur_x += pixels; + + /* limit panning to size of overall */ + + if (cur_x < 0) + cur_x = 0; + else + if (cur_x > (total_x - viewport_x)) + cur_x = total_x - viewport_x; + + SP->sb_cur_x = cur_x / font_width; + + XawScrollbarSetThumb(w, (double)((double)cur_x / (double)total_x), + (double)((double)viewport_x / (double)total_x)); + + _send_key_to_curses(KEY_SR, NULL, TRUE); +} + +static void _thumb_up_down(Widget w, XtPointer client_data, + XtPointer call_data) +{ + double percent = *(double *) call_data; + double total_y = (double)SP->sb_total_y; + double viewport_y = (double)SP->sb_viewport_y; + int cur_y = SP->sb_cur_y; + + /* If the size of the viewport is > overall area simply return, + as no scrolling is permitted. */ + + if (SP->sb_viewport_y >= SP->sb_total_y) + return; + + if ((SP->sb_cur_y = (int)((double)total_y * percent)) >= + (total_y - viewport_y)) + SP->sb_cur_y = total_y - viewport_y; + + XawScrollbarSetThumb(w, (double)(cur_y / total_y), + (double)(viewport_y / total_y)); + + _send_key_to_curses(KEY_SF, NULL, TRUE); +} + +static void _thumb_left_right(Widget w, XtPointer client_data, + XtPointer call_data) +{ + double percent = *(double *) call_data; + double total_x = (double)SP->sb_total_x; + double viewport_x = (double)SP->sb_viewport_x; + int cur_x = SP->sb_cur_x; + + if (SP->sb_viewport_x >= SP->sb_total_x) + return; + + if ((SP->sb_cur_x = (int)((float)total_x * percent)) >= + (total_x - viewport_x)) + SP->sb_cur_x = total_x - viewport_x; + + XawScrollbarSetThumb(w, (double)(cur_x / total_x), + (double)(viewport_x / total_x)); + + _send_key_to_curses(KEY_SR, NULL, TRUE); +} + +static void _exit_process(int rc, int sig, char *msg) +{ + if (rc || sig) + fprintf(stderr, "%s:_exit_process() - called: rc:%d sig:%d <%s>\n", + XCLOGMSG, rc, sig, msg); + + shmdt((char *)SP); + shmdt((char *)Xcurscr); + shmctl(shmidSP, IPC_RMID, 0); + shmctl(shmid_Xcurscr, IPC_RMID, 0); + + if (bitmap_file) + { + XFreePixmap(XCURSESDISPLAY, icon_bitmap); + free(bitmap_file); + } + +#ifdef HAVE_XPM_H + if (pixmap_file) + { + XFreePixmap(XCURSESDISPLAY, icon_pixmap); + XFreePixmap(XCURSESDISPLAY, icon_pixmap_mask); + free(pixmap_file); + } +#endif + XFreeGC(XCURSESDISPLAY, normal_gc); + XFreeGC(XCURSESDISPLAY, italic_gc); + XFreeGC(XCURSESDISPLAY, block_cursor_gc); + XFreeGC(XCURSESDISPLAY, rect_cursor_gc); + XFreeGC(XCURSESDISPLAY, border_gc); +#ifdef PDC_XIM + XDestroyIC(Xic); +#endif + + shutdown(xc_display_sock, 2); + close(xc_display_sock); + + shutdown(xc_exit_sock, 2); + close(xc_exit_sock); + + shutdown(xc_key_sock, 2); + close(xc_key_sock); + + if (sig) + kill(xc_otherpid, sig); /* to kill parent process */ + + _exit(rc); +} + +static void _resize(void) +{ + short save_atrtab[PDC_COLOR_PAIRS * 2]; + + after_first_curses_request = FALSE; + + SP->lines = XCursesLINES = ((resize_window_height - + (2 * xc_app_data.borderWidth)) / font_height); + + LINES = XCursesLINES - SP->linesrippedoff - SP->slklines; + + SP->cols = COLS = XCursesCOLS = ((resize_window_width - + (2 * xc_app_data.borderWidth)) / font_width); + + window_width = resize_window_width; + window_height = resize_window_height; + visible_cursor = TRUE; + + _draw_border(); + + /* Detach and drop the current shared memory segment and create and + attach to a new segment */ + + memcpy(save_atrtab, xc_atrtab, sizeof(save_atrtab)); + + SP->XcurscrSize = XCURSCR_SIZE; + shmdt((char *)Xcurscr); + shmctl(shmid_Xcurscr, IPC_RMID, 0); + + if ((shmid_Xcurscr = shmget(shmkey_Xcurscr, + SP->XcurscrSize + XCURSESSHMMIN, 0700 | IPC_CREAT)) < 0) + { + perror("Cannot allocate shared memory for curscr"); + + _exit_process(4, SIGKILL, "exiting from _process_curses_requests"); + } + + Xcurscr = (unsigned char*)shmat(shmid_Xcurscr, 0, 0); + memset(Xcurscr, 0, SP->XcurscrSize); + xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF); + memcpy(xc_atrtab, save_atrtab, sizeof(save_atrtab)); +} + +/* For PDC_set_title() */ + +static void _set_title(void) +{ + char title[1024]; /* big enough for window title */ + int pos; + + if ((XC_read_socket(xc_display_sock, &pos, sizeof(int)) < 0) || + (XC_read_socket(xc_display_sock, title, pos) < 0)) + { + _exit_process(5, SIGKILL, "exiting from _set_title"); + } + + XtVaSetValues(topLevel, XtNtitle, title, NULL); +} + +/* For color_content() */ + +static void _get_color(void) +{ + XColor *tmp = (XColor *)(Xcurscr + XCURSCR_XCOLOR_OFF); + int index = tmp->pixel; + Colormap cmap = DefaultColormap(XCURSESDISPLAY, + DefaultScreen(XCURSESDISPLAY)); + + if (index < 0 || index >= MAX_COLORS) + _exit_process(4, SIGKILL, "exiting from _get_color"); + + tmp->pixel = colors[index]; + XQueryColor(XCURSESDISPLAY, cmap, tmp); +} + +/* For init_color() */ + +static void _set_color(void) +{ + XColor *tmp = (XColor *)(Xcurscr + XCURSCR_XCOLOR_OFF); + int index = tmp->pixel; + Colormap cmap = DefaultColormap(XCURSESDISPLAY, + DefaultScreen(XCURSESDISPLAY)); + + if (index < 0 || index >= MAX_COLORS) + _exit_process(4, SIGKILL, "exiting from _set_color"); + + if (XAllocColor(XCURSESDISPLAY, cmap, tmp)) + { + XFreeColors(XCURSESDISPLAY, cmap, colors + index, 1, 0); + colors[index] = tmp->pixel; + + _display_screen(); + } +} + +/* For PDC_getclipboard() */ + +static void _get_selection(Widget w, XtPointer data, Atom *selection, + Atom *type, XtPointer value, + unsigned long *length, int *format) +{ + unsigned char *src = value; + int pos, len = *length; + + XC_LOG(("_get_selection() - called\n")); + + if (!value && !len) + { + if (XC_write_display_socket_int(PDC_CLIP_EMPTY) < 0) + _exit_process(4, SIGKILL, "exiting from _get_selection"); + } + else + { + /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then + contents */ + + if (XC_write_display_socket_int(PDC_CLIP_SUCCESS) < 0) + _exit_process(4, SIGKILL, "exiting from _get_selection"); + + if (XC_write_display_socket_int(len) < 0) + _exit_process(4, SIGKILL, "exiting from _get_selection"); + + for (pos = 0; pos < len; pos++) + { +#ifdef PDC_WIDE + wchar_t c; +#else + unsigned char c; +#endif + c = *src++; + + if (XC_write_socket(xc_display_sock, &c, sizeof(c)) < 0) + _exit_process(4, SIGKILL, "exiting from _get_selection"); + } + } +} + +#ifdef PDC_WIDE +static void _get_selection_utf8(Widget w, XtPointer data, Atom *selection, + Atom *type, XtPointer value, + unsigned long *length, int *format) +{ + int len = *length; + + XC_LOG(("_get_selection_utf8() - called\n")); + + if (!*type || !*length) + { + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _get_selection, + (XtPointer)NULL, 0); + return; + } + + if (!value && !len) + { + if (XC_write_display_socket_int(PDC_CLIP_EMPTY) >= 0) + return; + } + else + { + wchar_t *wcontents = malloc((len + 1) * sizeof(wchar_t)); + char *src = value; + int i = 0; + + while (*src && i < (*length)) + { + int retval = _from_utf8(wcontents + i, src, len); + + src += retval; + len -= retval; + i++; + } + + wcontents[i] = 0; + len = i; + + /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then + contents */ + + if (XC_write_display_socket_int(PDC_CLIP_SUCCESS) >= 0) + if (XC_write_display_socket_int(len) >= 0) + if (XC_write_socket(xc_display_sock, + wcontents, len * sizeof(wchar_t)) >= 0) + { + free(wcontents); + return; + } + } + + _exit_process(4, SIGKILL, "exiting from _get_selection_utf8"); +} +#endif + +/* For PDC_setclipboard() */ + +static void _set_selection(void) +{ + long length, pos; + int status; + + if (XC_read_socket(xc_display_sock, &length, sizeof(long)) < 0) + _exit_process(5, SIGKILL, "exiting from _set_selection"); + + if (length > (long)tmpsel_length) + { + if (!tmpsel_length) + tmpsel = malloc((length + 1) * sizeof(chtype)); + else + tmpsel = realloc(tmpsel, (length + 1) * sizeof(chtype)); + } + + if (!tmpsel) + if (XC_write_display_socket_int(PDC_CLIP_MEMORY_ERROR) < 0) + _exit_process(4, SIGKILL, "exiting from _set_selection"); + + for (pos = 0; pos < length; pos++) + { +#ifdef PDC_WIDE + wchar_t c; +#else + unsigned char c; +#endif + if (XC_read_socket(xc_display_sock, &c, sizeof(c)) < 0) + _exit_process(5, SIGKILL, "exiting from _set_selection"); + + tmpsel[pos] = c; + } + + tmpsel_length = length; + tmpsel[length] = 0; + + if (XtOwnSelection(topLevel, XA_PRIMARY, CurrentTime, + _convert_proc, _lose_ownership, NULL) == False) + { + status = PDC_CLIP_ACCESS_ERROR; + free(tmpsel); + tmpsel = NULL; + tmpsel_length = 0; + } + else + status = PDC_CLIP_SUCCESS; + + _selection_off(); + + if (XC_write_display_socket_int(status) < 0) + _exit_process(4, SIGKILL, "exiting from _set_selection"); +} + +/* The curses process is waiting; tell it to continue */ + +static void _resume_curses(void) +{ + if (XC_write_display_socket_int(CURSES_CONTINUE) < 0) + _exit_process(4, SIGKILL, "exiting from _process_curses_requests"); +} + +/* The curses process sent us a message */ + +static void _process_curses_requests(XtPointer client_data, int *fid, + XtInputId *id) +{ + struct timeval socket_timeout = {0}; + int s; + int old_row, new_row; + int old_x, new_x; + int pos, num_cols; + + char buf[12]; /* big enough for 2 integers */ + + XC_LOG(("_process_curses_requests() - called\n")); + + if (!received_map_notify) + return; + + FD_ZERO(&xc_readfds); + FD_SET(xc_display_sock, &xc_readfds); + + if ((s = select(FD_SETSIZE, (FD_SET_CAST)&xc_readfds, NULL, + NULL, &socket_timeout)) < 0) + _exit_process(2, SIGKILL, "exiting from _process_curses_requests" + " - select failed"); + + if (!s) /* no requests pending - should never happen! */ + return; + + if (FD_ISSET(xc_display_sock, &xc_readfds)) + { + /* read first integer to determine total message has been + received */ + + XC_LOG(("_process_curses_requests() - before XC_read_socket()\n")); + + if (XC_read_socket(xc_display_sock, &num_cols, sizeof(int)) < 0) + _exit_process(3, SIGKILL, "exiting from _process_curses_requests" + " - first read"); + + XC_LOG(("_process_curses_requests() - after XC_read_socket()\n")); + + after_first_curses_request = TRUE; + + switch(num_cols) + { + case CURSES_EXIT: /* request from curses to stop */ + XC_LOG(("CURSES_EXIT received from child\n")); + _exit_process(0, 0, "XCursesProcess requested to exit by child"); + break; + + case CURSES_BELL: + XC_LOG(("CURSES_BELL received from child\n")); + XBell(XCURSESDISPLAY, 50); + break; + + /* request from curses to confirm completion of display */ + + case CURSES_REFRESH: + XC_LOG(("CURSES_REFRESH received from child\n")); + _refresh_screen(); + _resume_curses(); + break; + + case CURSES_REFRESH_SCROLLBAR: + _refresh_scrollbar(); + break; + + case CURSES_CURSOR: + XC_LOG(("CURSES_CURSOR received from child\n")); + + if (XC_read_socket(xc_display_sock, buf, sizeof(int) * 2) < 0) + _exit_process(5, SIGKILL, "exiting from CURSES_CURSOR " + "_process_curses_requests"); + + memcpy(&pos, buf, sizeof(int)); + old_row = pos & 0xFF; + old_x = pos >> 8; + + memcpy(&pos, buf + sizeof(int), sizeof(int)); + new_row = pos & 0xFF; + new_x = pos >> 8; + + visible_cursor = TRUE; + _display_cursor(old_row, old_x, new_row, new_x); + break; + + case CURSES_DISPLAY_CURSOR: + XC_LOG(("CURSES_DISPLAY_CURSOR received from child. Vis now: ")); + XC_LOG((visible_cursor ? "1\n" : "0\n")); + + /* If the window is not active, ignore this command. The + cursor will stay solid. */ + + if (window_entered) + { + if (visible_cursor) + { + /* Cursor currently ON, turn it off */ + + int save_visibility = SP->visibility; + SP->visibility = 0; + _redraw_cursor(); + SP->visibility = save_visibility; + visible_cursor = FALSE; + } + else + { + /* Cursor currently OFF, turn it on */ + + _redraw_cursor(); + visible_cursor = TRUE; + } + } + + break; + + case CURSES_TITLE: + XC_LOG(("CURSES_TITLE received from child\n")); + _set_title(); + break; + + case CURSES_RESIZE: + XC_LOG(("CURSES_RESIZE received from child\n")); + _resize(); + _resume_curses(); + break; + + case CURSES_GET_SELECTION: + XC_LOG(("CURSES_GET_SELECTION received from child\n")); + + _resume_curses(); + + XtGetSelectionValue(topLevel, XA_PRIMARY, +#ifdef PDC_WIDE + XA_UTF8_STRING(XtDisplay(topLevel)), + _get_selection_utf8, +#else + XA_STRING, _get_selection, +#endif + (XtPointer)NULL, 0); + + break; + + case CURSES_SET_SELECTION: + XC_LOG(("CURSES_SET_SELECTION received from child\n")); + _set_selection(); + break; + + case CURSES_CLEAR_SELECTION: + XC_LOG(("CURSES_CLEAR_SELECTION received from child\n")); + _resume_curses(); + _selection_off(); + break; + + case CURSES_GET_COLOR: + XC_LOG(("CURSES_GET_COLOR recieved from child\n")); + _get_color(); + _resume_curses(); + break; + + case CURSES_SET_COLOR: + XC_LOG(("CURSES_SET_COLOR recieved from child\n")); + _set_color(); + _resume_curses(); + break; + + default: + PDC_LOG(("%s:Unknown request %d\n", XCLOGMSG, num_cols)); + } + } +} + +static void _handle_structure_notify(Widget w, XtPointer client_data, + XEvent *event, Boolean *unused) +{ + XC_LOG(("_handle_structure_notify() - called\n")); + + switch(event->type) + { + case ConfigureNotify: + XC_LOG(("ConfigureNotify received\n")); + + /* Window has been resized, change width and height to send to + place_text and place_graphics in next Expose. Also will need + to kill (SIGWINCH) curses process if screen size changes. */ + + resize_window_width = event->xconfigure.width; + resize_window_height = event->xconfigure.height; + + after_first_curses_request = FALSE; + +#ifdef SIGWINCH + SP->resized = 1; + + kill(xc_otherpid, SIGWINCH); +#endif + _send_key_to_curses(KEY_RESIZE, NULL, TRUE); + break; + + case MapNotify: + XC_LOG(("MapNotify received\n")); + + received_map_notify = 1; + + _draw_border(); + break; + + default: + PDC_LOG(("%s:_handle_structure_notify - unknown event %d\n", + XCLOGMSG, event->type)); + } +} + +static RETSIGTYPE _handle_signals(int signo) +{ + int flag = CURSES_EXIT; + + PDC_LOG(("%s:_handle_signals() - called: %d\n", XCLOGMSG, signo)); + + /* Patch by: Georg Fuchs */ + + XCursesSetSignal(signo, _handle_signals); + +#ifdef SIGTSTP + if (signo == SIGTSTP) + { + pause(); + return; + } +#endif +#ifdef SIGCONT + if (signo == SIGCONT) + return; +#endif +#ifdef SIGCLD + if (signo == SIGCLD) + return; +#endif +#ifdef SIGTTIN + if (signo == SIGTTIN) + return; +#endif +#ifdef SIGWINCH + if (signo == SIGWINCH) + return; +#endif + + /* End of patch by: Georg Fuchs */ + + XCursesSetSignal(signo, SIG_IGN); + + /* Send a CURSES_EXIT to myself */ + + if (XC_write_socket(xc_exit_sock, &flag, sizeof(int)) < 0) + _exit_process(7, signo, "exiting from _handle_signals"); +} + +#ifdef PDC_XIM +static void _dummy_handler(Widget w, XtPointer client_data, + XEvent *event, Boolean *unused) +{ +} +#endif + +int XCursesSetupX(int argc, char *argv[]) +{ + char *myargv[] = {"PDCurses", NULL}; + extern bool sb_started; + + int italic_font_valid; + XColor pointerforecolor, pointerbackcolor; + XrmValue rmfrom, rmto; + int i = 0; + int minwidth, minheight; + + XC_LOG(("XCursesSetupX called\n")); + + if (!argv) + { + argv = myargv; + argc = 1; + } + + program_name = argv[0]; + + /* Keep open the 'write' end of the socket so the XCurses process + can send a CURSES_EXIT to itself from within the signal handler */ + + xc_exit_sock = xc_display_sockets[0]; + xc_display_sock = xc_display_sockets[1]; + + close(xc_key_sockets[0]); + xc_key_sock = xc_key_sockets[1]; + + /* Trap all signals when XCurses is the child process, but only if + they haven't already been ignored by the application. */ + + for (i = 0; i < PDC_MAX_SIGNALS; i++) + if (XCursesSetSignal(i, _handle_signals) == SIG_IGN) + XCursesSetSignal(i, SIG_IGN); + + /* Start defining X Toolkit things */ + +#if XtSpecificationRelease > 4 + XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL); +#endif + + /* Exit if no DISPLAY variable set */ + + if (!getenv("DISPLAY")) + { + fprintf(stderr, "Error: no DISPLAY variable set\n"); + kill(xc_otherpid, SIGKILL); + return ERR; + } + + /* Initialise the top level widget */ + + topLevel = XtVaAppInitialize(&app_context, class_name, options, + XtNumber(options), &argc, argv, NULL, NULL); + + XtVaGetApplicationResources(topLevel, &xc_app_data, app_resources, + XtNumber(app_resources), NULL); + + /* Check application resource values here */ + + font_width = xc_app_data.normalFont->max_bounds.rbearing - + xc_app_data.normalFont->min_bounds.lbearing; + + font_height = xc_app_data.normalFont->max_bounds.ascent + + xc_app_data.normalFont->max_bounds.descent; + + font_ascent = xc_app_data.normalFont->max_bounds.ascent; + font_descent = xc_app_data.normalFont->max_bounds.descent; + + /* Check that the italic font and normal fonts are the same size */ + /* This appears backwards */ + + italic_font_valid = font_width != + xc_app_data.italicFont->max_bounds.rbearing - + xc_app_data.italicFont->min_bounds.lbearing || + font_height != + xc_app_data.italicFont->max_bounds.ascent + + xc_app_data.italicFont->max_bounds.descent; + + /* Calculate size of display window */ + + XCursesCOLS = xc_app_data.cols; + XCursesLINES = xc_app_data.lines; + + window_width = font_width * XCursesCOLS + + 2 * xc_app_data.borderWidth; + + window_height = font_height * XCursesLINES + + 2 * xc_app_data.borderWidth; + + minwidth = font_width * 2 + xc_app_data.borderWidth * 2; + minheight = font_height * 2 + xc_app_data.borderWidth * 2; + + /* Set up the icon for the application; the default is an internal + one for PDCurses. Then set various application level resources. */ + + _get_icon(); + +#ifdef HAVE_XPM_H + if (xc_app_data.pixmap && xc_app_data.pixmap[0]) + XtVaSetValues(topLevel, XtNminWidth, minwidth, XtNminHeight, + minheight, XtNbaseWidth, xc_app_data.borderWidth * 2, + XtNbaseHeight, xc_app_data.borderWidth * 2, + XtNiconPixmap, icon_pixmap, + XtNiconMask, icon_pixmap_mask, NULL); + else +#endif + XtVaSetValues(topLevel, XtNminWidth, minwidth, XtNminHeight, + minheight, XtNbaseWidth, xc_app_data.borderWidth * 2, + XtNbaseHeight, xc_app_data.borderWidth * 2, + XtNiconPixmap, icon_bitmap, NULL); + + /* Create a BOX widget in which to draw */ + + if (xc_app_data.scrollbarWidth && sb_started) + { + scrollBox = XtVaCreateManagedWidget(program_name, + scrollBoxWidgetClass, topLevel, XtNwidth, + window_width + xc_app_data.scrollbarWidth, + XtNheight, window_height + xc_app_data.scrollbarWidth, + XtNwidthInc, font_width, XtNheightInc, font_height, NULL); + + drawing = XtVaCreateManagedWidget(program_name, + boxWidgetClass, scrollBox, XtNwidth, + window_width, XtNheight, window_height, XtNwidthInc, + font_width, XtNheightInc, font_height, NULL); + + scrollVert = XtVaCreateManagedWidget("scrollVert", + scrollbarWidgetClass, scrollBox, XtNorientation, + XtorientVertical, XtNheight, window_height, XtNwidth, + xc_app_data.scrollbarWidth, NULL); + + XtAddCallback(scrollVert, XtNscrollProc, _scroll_up_down, drawing); + XtAddCallback(scrollVert, XtNjumpProc, _thumb_up_down, drawing); + + scrollHoriz = XtVaCreateManagedWidget("scrollHoriz", + scrollbarWidgetClass, scrollBox, XtNorientation, + XtorientHorizontal, XtNwidth, window_width, XtNheight, + xc_app_data.scrollbarWidth, NULL); + + XtAddCallback(scrollHoriz, XtNscrollProc, _scroll_left_right, drawing); + XtAddCallback(scrollHoriz, XtNjumpProc, _thumb_left_right, drawing); + } + else + { + drawing = XtVaCreateManagedWidget(program_name, boxWidgetClass, + topLevel, XtNwidth, window_width, XtNheight, window_height, + XtNwidthInc, font_width, XtNheightInc, font_height, NULL); + + XtVaSetValues(topLevel, XtNwidthInc, font_width, XtNheightInc, + font_height, NULL); + } + + /* Process any default translations */ + + XtAugmentTranslations(drawing, + XtParseTranslationTable(default_translations)); + XtAppAddActions(app_context, action_table, XtNumber(action_table)); + + /* Process the supplied colors */ + + _initialize_colors(); + + /* Determine text cursor alignment from resources */ + + if (!strcmp(xc_app_data.textCursor, "vertical")) + vertical_cursor = TRUE; + + /* Now have LINES and COLS. Set these in the shared SP so the curses + program can find them. */ + + LINES = XCursesLINES; + COLS = XCursesCOLS; + + if ((shmidSP = shmget(shmkeySP, sizeof(SCREEN) + XCURSESSHMMIN, + 0700 | IPC_CREAT)) < 0) + { + perror("Cannot allocate shared memory for SCREEN"); + kill(xc_otherpid, SIGKILL); + return ERR; + } + + SP = (SCREEN*)shmat(shmidSP, 0, 0); + memset(SP, 0, sizeof(SCREEN)); + SP->XcurscrSize = XCURSCR_SIZE; + SP->lines = XCursesLINES; + SP->cols = XCursesCOLS; + + SP->mouse_wait = xc_app_data.clickPeriod; + SP->audible = TRUE; + + PDC_LOG(("%s:SHM size for curscr %d\n", XCLOGMSG, SP->XcurscrSize)); + + if ((shmid_Xcurscr = shmget(shmkey_Xcurscr, SP->XcurscrSize + + XCURSESSHMMIN, 0700 | IPC_CREAT)) < 0) + { + perror("Cannot allocate shared memory for curscr"); + kill(xc_otherpid, SIGKILL); + shmdt((char *)SP); + shmctl(shmidSP, IPC_RMID, 0); + return ERR; + } + + Xcurscr = (unsigned char *)shmat(shmid_Xcurscr, 0, 0); + memset(Xcurscr, 0, SP->XcurscrSize); + xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF); + + PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n", + XCLOGMSG, shmid_Xcurscr, shmkey_Xcurscr, LINES, COLS)); + + /* Add Event handlers to the drawing widget */ + + XtAddEventHandler(drawing, ExposureMask, False, _handle_expose, NULL); + XtAddEventHandler(drawing, StructureNotifyMask, False, + _handle_structure_notify, NULL); + XtAddEventHandler(drawing, EnterWindowMask | LeaveWindowMask, False, + _handle_enter_leave, NULL); + XtAddEventHandler(topLevel, 0, True, _handle_nonmaskable, NULL); + + /* Add input handler from xc_display_sock (requests from curses + program) */ + + XtAppAddInput(app_context, xc_display_sock, (XtPointer)XtInputReadMask, + _process_curses_requests, NULL); + + /* If there is a cursorBlink resource, start the Timeout event */ + + if (xc_app_data.cursorBlinkRate) + XtAppAddTimeOut(app_context, xc_app_data.cursorBlinkRate, + _blink_cursor, NULL); + + /* Leave telling the curses process that it can start to here so + that when the curses process makes a request, the Xcurses + process can service the request. */ + + XC_write_display_socket_int(CURSES_CHILD); + + XtRealizeWidget(topLevel); + + /* Handle trapping of the WM_DELETE_WINDOW property */ + + wm_atom[0] = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", False); + + XSetWMProtocols(XtDisplay(topLevel), XtWindow(topLevel), wm_atom, 1); + + /* Create the Graphics Context for drawing. This MUST be done AFTER + the associated widget has been realized. */ + + XC_LOG(("before _get_gc\n")); + + _get_gc(&normal_gc, xc_app_data.normalFont, COLOR_WHITE, COLOR_BLACK); + + _get_gc(&italic_gc, italic_font_valid ? xc_app_data.italicFont : + xc_app_data.normalFont, COLOR_WHITE, COLOR_BLACK); + + _get_gc(&block_cursor_gc, xc_app_data.normalFont, + COLOR_BLACK, COLOR_CURSOR); + + _get_gc(&rect_cursor_gc, xc_app_data.normalFont, + COLOR_CURSOR, COLOR_BLACK); + + _get_gc(&border_gc, xc_app_data.normalFont, COLOR_BORDER, COLOR_BLACK); + + XSetLineAttributes(XCURSESDISPLAY, rect_cursor_gc, 2, + LineSolid, CapButt, JoinMiter); + + XSetLineAttributes(XCURSESDISPLAY, border_gc, xc_app_data.borderWidth, + LineSolid, CapButt, JoinMiter); + + /* Set the cursor for the application */ + + XDefineCursor(XCURSESDISPLAY, XCURSESWIN, xc_app_data.pointer); + rmfrom.size = sizeof(Pixel); + rmto.size = sizeof(XColor); + + rmto.addr = (XPointer)&pointerforecolor; + rmfrom.addr = (XPointer)&(xc_app_data.pointerForeColor); + XtConvertAndStore(drawing, XtRPixel, &rmfrom, XtRColor, &rmto); + + rmfrom.size = sizeof(Pixel); + rmto.size = sizeof(XColor); + + rmfrom.addr = (XPointer)&(xc_app_data.pointerBackColor); + rmto.addr = (XPointer)&pointerbackcolor; + XtConvertAndStore(drawing, XtRPixel, &rmfrom, XtRColor, &rmto); + + XRecolorCursor(XCURSESDISPLAY, xc_app_data.pointer, + &pointerforecolor, &pointerbackcolor); + +#ifndef PDC_XIM + + /* Convert the supplied compose key to a Keysym */ + + compose_key = XStringToKeysym(xc_app_data.composeKey); + + if (compose_key && IsModifierKey(compose_key)) + { + int i, j; + KeyCode *kcp; + XModifierKeymap *map; + KeyCode compose_keycode = XKeysymToKeycode(XCURSESDISPLAY, compose_key); + + map = XGetModifierMapping(XCURSESDISPLAY); + kcp = map->modifiermap; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < map->max_keypermod; j++, kcp++) + { + if (!*kcp) + continue; + + if (compose_keycode == *kcp) + { + compose_mask = state_mask[i]; + break; + } + } + + if (compose_mask) + break; + } + + XFreeModifiermap(map); + } + +#else + Xim = XOpenIM(XCURSESDISPLAY, NULL, NULL, NULL); + + if (Xim) + { + Xic = XCreateIC(Xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, XCURSESWIN, NULL); + } + + if (Xic) + { + long im_event_mask; + + XGetICValues(Xic, XNFilterEvents, &im_event_mask, NULL); + if (im_event_mask) + XtAddEventHandler(drawing, im_event_mask, False, + _dummy_handler, NULL); + + XSetICFocus(Xic); + } + else + { + perror("ERROR: Cannot create input context"); + kill(xc_otherpid, SIGKILL); + shmdt((char *)SP); + shmdt((char *)Xcurscr); + shmctl(shmidSP, IPC_RMID, 0); + shmctl(shmid_Xcurscr, IPC_RMID, 0); + return ERR; + } + +#endif + + /* Wait for events */ + + XtAppMainLoop(app_context); + return OK; /* won't get here */ +} |