aboutsummaryrefslogtreecommitdiff
path: root/payloads/libpayload/curses/PDCurses-3.4/x11/x11.c
diff options
context:
space:
mode:
authorPatrick Georgi <patrick.georgi@secunet.com>2011-07-07 15:41:53 +0200
committerStefan Reinauer <stefan.reinauer@coreboot.org>2011-08-04 08:10:41 +0200
commit3b77b723ca209199c8a224702812441e2196d452 (patch)
treecbf3be2c724139ec80a33dbf8e002b7871ef9307 /payloads/libpayload/curses/PDCurses-3.4/x11/x11.c
parent1ac19e28eed4f6c53a4f295eb55500c65fc80f8d (diff)
libpayload: Add PDCurses and ncurses' libform/libmenu
PDCurses provides an alternative implementation of the curses library standard in addition to tinycurses. Where tinycurses is really tiny, PDCurses is more complete and provides virtually unlimited windows and the full API. The PDCurses code is brought in "vanilla", with all local changes residing in curses/pdcurses-backend/ In addition to a curses library, this change also provides libpanel (as part of the PDCurses code), and libform and libmenu which were derived from ncurses-5.9. As they rely on ncurses internals (and PDCurses is not ncurses), more changes were required for these libraries to work. The build system is extended to install the right set of header files depending on the selected curses implementation. Change-Id: I9e5b920f94b6510da01da2f656196a993170d1c5 Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com> Reviewed-on: http://review.coreboot.org/106 Tested-by: build bot (Jenkins) Reviewed-by: Marc Jones <marcj303@gmail.com>
Diffstat (limited to 'payloads/libpayload/curses/PDCurses-3.4/x11/x11.c')
-rw-r--r--payloads/libpayload/curses/PDCurses-3.4/x11/x11.c3229
1 files changed, 3229 insertions, 0 deletions
diff --git a/payloads/libpayload/curses/PDCurses-3.4/x11/x11.c b/payloads/libpayload/curses/PDCurses-3.4/x11/x11.c
new file mode 100644
index 0000000000..97d44985e5
--- /dev/null
+++ b/payloads/libpayload/curses/PDCurses-3.4/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 */
+}