Change-Id: If881ec130833c7e7e62caa3d31e350a531f5bc8e Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-on: http://review.coreboot.org/12398 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
		
			
				
	
	
		
			3230 lines
		
	
	
		
			91 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3230 lines
		
	
	
		
			91 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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 */
 | |
| }
 |