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