|
|
1.1 ! root 1: /* X Communication module for terminals which understand the X protocol. ! 2: Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 1, or (at your option) ! 9: any later version. ! 10: ! 11: GNU Emacs is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU Emacs; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: /* Written by Yakim Martillo, mods and things by Robert Krawitz */ ! 21: ! 22: /* ! 23: * $Source: /u2/third_party/gnuemacs.chow/src/RCS/xterm.c,v $ ! 24: * $Author: rlk $ ! 25: * $Locker: $ ! 26: * $Header: xterm.c,v 1.28 86/08/27 13:30:57 rlk Exp $ ! 27: */ ! 28: ! 29: #ifndef lint ! 30: static char *rcsid_TrmXTERM_c = "$Header: xterm.c,v 1.28 86/08/27 13:30:57 rlk Exp $"; ! 31: #endif lint ! 32: ! 33: /* On 4.3 this loses if it comes after xterm.h. */ ! 34: #include <signal.h> ! 35: #include "config.h" ! 36: ! 37: #ifdef HAVE_X_WINDOWS ! 38: ! 39: #include "lisp.h" ! 40: #undef NULL ! 41: ! 42: /* This may include sys/types.h, and that somehow loses ! 43: if this is not done before the other system files. */ ! 44: #include "xterm.h" ! 45: ! 46: /* Load sys/types.h if not already loaded. ! 47: In some systems loading it twice is suicidal. */ ! 48: #ifndef makedev ! 49: #include <sys/types.h> ! 50: #endif ! 51: ! 52: #if !defined(USG) || defined(IBMRTAIX) ! 53: #include <sys/time.h> ! 54: #else ! 55: #include <time.h> ! 56: #endif /* USG and not IBMRTAIX */ ! 57: ! 58: #include <sys/ioctl.h> ! 59: #include <fcntl.h> ! 60: #include <stdio.h> ! 61: #include <ctype.h> ! 62: #include <errno.h> ! 63: #ifdef BSD ! 64: #include <strings.h> ! 65: #endif ! 66: #include <sys/stat.h> ! 67: ! 68: #include "dispextern.h" ! 69: #include "termhooks.h" ! 70: #include "termopts.h" ! 71: #include "termchar.h" ! 72: #include "sink.h" ! 73: #include "sinkmask.h" ! 74: #include <X/Xkeyboard.h> ! 75: /*#include <X/Xproto.h> */ ! 76: ! 77: /* Allow m- file to inhibit use of FIONREAD. */ ! 78: #ifdef BROKEN_FIONREAD ! 79: #undef FIONREAD ! 80: #endif ! 81: ! 82: /* We are unable to use interrupts if FIONREAD is not available, ! 83: so flush SIGIO so we won't try. */ ! 84: #ifndef FIONREAD ! 85: #ifdef SIGIO ! 86: #undef SIGIO ! 87: #endif ! 88: #endif ! 89: ! 90: /* Allow config to specify default font. */ ! 91: #ifndef X_DEFAULT_FONT ! 92: #define X_DEFAULT_FONT "vtsingle" ! 93: #endif ! 94: ! 95: #define min(a,b) ((a)<(b) ? (a) : (b)) ! 96: #define max(a,b) ((a)>(b) ? (a) : (b)) ! 97: #define sigunblockx(sig) sigblock (0) ! 98: #define sigblockx(sig) sigblock (1 << ((sig) - 1)) ! 99: XREPBUFFER Xxrepbuffer; ! 100: int pixelwidth; ! 101: int pixelheight; ! 102: int PendingExposure; ! 103: int PendingIconExposure; ! 104: #define MAXICID 80 ! 105: char iconidentity[MAXICID]; ! 106: #define ICONTAG "emacs@" ! 107: #define METABIT 0x80 ! 108: Window XXIconWindow; ! 109: Bitmap XXIconMask; ! 110: ! 111: char *XXcurrentfont; ! 112: char *default_window; ! 113: int informflag; ! 114: extern int initialized; ! 115: ! 116: extern char *alternate_display; ! 117: ! 118: int XXdebug; ! 119: int XXpid; ! 120: extern int screen_garbaged; ! 121: int XXxoffset, XXyoffset; ! 122: int IconWindow; ! 123: ! 124: int WindowMapped; ! 125: int CurHL; ! 126: ! 127: static int flexlines; /* last line affect by dellines or */ ! 128: /* inslines functions */ ! 129: extern int errno; ! 130: int VisibleX, VisibleY; /* genuine location of cursor on screen */ ! 131: /* if it is there */ ! 132: static int SavedX, SavedY; /* Where the cursor was before update */ ! 133: /* started */ ! 134: ! 135: int bitblt; /* Used to track bit blt events */ ! 136: int CursorExists; /* during updates cursor is turned off */ ! 137: static int InUpdate; /* many of functions here may be invoked */ ! 138: /* even if no update in progress, when */ ! 139: /* no update is in progress the action */ ! 140: /* can be slightly different */ ! 141: ! 142: short MouseCursor[] = { ! 143: 0x0000, 0x0008, 0x0018, 0x0038, ! 144: 0x0078, 0x00f8, 0x01f8, 0x03f8, ! 145: 0x07f8, 0x00f8, 0x00d8, 0x0188, ! 146: 0x0180, 0x0300, 0x0300, 0x0000}; ! 147: ! 148: short MouseMask[] = { ! 149: 0x000c, 0x001c, 0x003c, 0x007c, ! 150: 0x00fc, 0x01fc, 0x03fc, 0x07fc, ! 151: 0x0ffc, 0x0ffc, 0x01fc, 0x03dc, ! 152: 0x03cc, 0x0780, 0x0780, 0x0300}; ! 153: ! 154: Display *XXdisplay; ! 155: FontInfo *fontinfo; ! 156: Window XXwindow; ! 157: Cursor EmacsCursor; ! 158: ! 159: char *fore_color; /* Variables to store colors */ ! 160: char *back_color; ! 161: char *brdr_color; ! 162: char *curs_color; ! 163: char *mous_color; ! 164: ! 165: int fore; ! 166: int back; ! 167: int brdr; ! 168: int curs; ! 169: int mous; ! 170: ! 171: static WindowInfo windowinfo; ! 172: WindowInfo rootwindowinfo; ! 173: ! 174: ! 175: ! 176: static XKeyPressedEvent XXEvent; /* as X messages are read in they are */ ! 177: /* stored here */ ! 178: static XREPBUFFER XXqueue;/* Used for storing up ExposeRegion */ ! 179: /* replies, so that the SIGIO inter- */ ! 180: /* rupt serving routines do almost */ ! 181: /* no writes to the X socket */ ! 182: /*int CurHL; /* Current Highlighting actually being */ ! 183: /* being used for bold font right now*/ ! 184: ! 185: int XXborder; ! 186: int XXInternalBorder; ! 187: ! 188: int (*handler)(); ! 189: ! 190: extern Display *XOpenDisplay (); ! 191: extern Window XCreateWindow (); ! 192: extern Cursor XDefineCursor (); ! 193: extern Cursor XCreateCursor (); ! 194: extern FontInfo *XOpenFont (); ! 195: ! 196: static int flashback (); ! 197: ! 198: ! 199: /* HLmode -- Changes the GX function for output strings. Could be used to ! 200: * change font. Check an XText library function call. ! 201: */ ! 202: ! 203: static ! 204: HLmode (new) ! 205: int new; ! 206: { ! 207: CurHL = new; ! 208: } ! 209: ! 210: ! 211: /* External interface to control of standout mode. ! 212: Call this when about to modify line at position VPOS ! 213: and not change whether it is highlighted. */ ! 214: ! 215: XTreassert_line_highlight (highlight, vpos) ! 216: int highlight, vpos; ! 217: { ! 218: HLmode (highlight); ! 219: } ! 220: ! 221: /* Call this when about to modify line at position VPOS ! 222: and change whether it is highlighted. */ ! 223: ! 224: static ! 225: XTchange_line_highlight (new_highlight, vpos, first_unused_hpos) ! 226: int new_highlight, vpos, first_unused_hpos; ! 227: { ! 228: HLmode (new_highlight); ! 229: XTmove_cursor (vpos, 0); ! 230: x_clear_end_of_line (0); ! 231: } ! 232: ! 233: ! 234: /* Used for starting or restarting (after suspension) the X window. Puts the ! 235: * cursor in a known place, update does not begin with this routine but only ! 236: * with a call to redisplay. The mouse cursor is warped into the window and ! 237: * then the cursor is turned on. ! 238: */ ! 239: ! 240: ! 241: ! 242: static ! 243: XTset_terminal_modes () ! 244: { ! 245: int stuffpending; ! 246: #ifdef XDEBUG ! 247: fprintf (stderr, "XTset_terminal_modes\n"); ! 248: #endif ! 249: InUpdate = 0; ! 250: stuffpending = 0; ! 251: if (!initialized) ! 252: { ! 253: CursorExists = 0; ! 254: VisibleX = 0; ! 255: VisibleY = 0; ! 256: } ! 257: XTclear_screen (); ! 258: #ifdef FIONREAD ! 259: ioctl (0, FIONREAD, &stuffpending); ! 260: if (stuffpending) ! 261: SIGNAL_INPUT (); ! 262: #endif ! 263: } ! 264: ! 265: /* XTmove_cursor moves the cursor to the correct location and checks whether an update ! 266: * is in progress in order to toggle it on. ! 267: */ ! 268: ! 269: static ! 270: XTmove_cursor (row, col) ! 271: register int row, col; ! 272: { ! 273: BLOCK_INPUT_DECLARE () ! 274: ! 275: BLOCK_INPUT (); ! 276: #ifdef XDEBUG ! 277: fprintf (stderr, "XTmove_cursor\n"); ! 278: #endif ! 279: cursor_hpos = col; ! 280: cursor_vpos = row; ! 281: if (InUpdate) ! 282: { ! 283: if (CursorExists) ! 284: { ! 285: CursorToggle (); ! 286: } ! 287: UNBLOCK_INPUT (); ! 288: return; /* Generally, XTmove_cursor will be invoked */ ! 289: /* when InUpdate with !CursorExists */ ! 290: /* so that wasteful XFlush is not called */ ! 291: } ! 292: if ((row == VisibleY) && (col == VisibleX)) ! 293: { ! 294: if (!CursorExists) ! 295: { ! 296: CursorToggle (); ! 297: } ! 298: XFlush (); ! 299: UNBLOCK_INPUT (); ! 300: return; ! 301: } ! 302: if (CursorExists) CursorToggle (); ! 303: VisibleX = col; ! 304: VisibleY = row; ! 305: if (!CursorExists) CursorToggle (); ! 306: XFlush (); ! 307: UNBLOCK_INPUT (); ! 308: } ! 309: ! 310: /* Used to get the terminal back to a known state after resets. Usually ! 311: * used when restarting suspended or waiting emacs ! 312: */ ! 313: ! 314: static ! 315: cleanup () ! 316: { ! 317: inverse_video = 0; ! 318: HLmode (0); ! 319: } ! 320: ! 321: /* Erase current line from column cursor_hpos to column END. ! 322: Leave cursor at END. */ ! 323: ! 324: static ! 325: XTclear_end_of_line (end) ! 326: register int end; ! 327: { ! 328: register int numcols; ! 329: ! 330: #ifdef XDEBUG ! 331: fprintf (stderr, "XTclear_end_of_line\n"); ! 332: ! 333: #endif ! 334: if (cursor_vpos < 0 || cursor_vpos >= screen_height) ! 335: { ! 336: return; ! 337: } ! 338: ! 339: if (end >= screen_width) ! 340: end = screen_width; ! 341: if (end <= cursor_hpos) ! 342: return; ! 343: ! 344: numcols = end - cursor_hpos; ! 345: { ! 346: BLOCK_INPUT_DECLARE () ! 347: ! 348: BLOCK_INPUT (); ! 349: if (cursor_vpos == VisibleY && VisibleX >= cursor_hpos && VisibleX < end) ! 350: { ! 351: if (CursorExists) CursorToggle (); ! 352: } ! 353: XPixSet (XXwindow, ! 354: cursor_hpos * fontinfo->width + XXInternalBorder, ! 355: cursor_vpos * fontinfo->height+XXInternalBorder, ! 356: fontinfo->width * numcols, ! 357: fontinfo->height, ! 358: back); ! 359: XTmove_cursor (cursor_vpos, end); ! 360: UNBLOCK_INPUT (); ! 361: } ! 362: } ! 363: ! 364: /* Erase current line from column START to right margin. ! 365: Leave cursor at START. */ ! 366: ! 367: static ! 368: x_clear_end_of_line (start) ! 369: register int start; ! 370: { ! 371: register int numcols; ! 372: ! 373: #ifdef XDEBUG ! 374: fprintf (stderr, "x_clear_end_of_line\n"); ! 375: ! 376: #endif ! 377: if (cursor_vpos < 0 || cursor_vpos >= screen_height) ! 378: { ! 379: return; ! 380: } ! 381: ! 382: if (start < 0) ! 383: start = 0; ! 384: if (start >= screen_width) ! 385: return; ! 386: ! 387: numcols = screen_width - start; ! 388: { ! 389: BLOCK_INPUT_DECLARE () ! 390: ! 391: BLOCK_INPUT (); ! 392: if (cursor_vpos == VisibleY && VisibleX >= start) ! 393: { ! 394: if (CursorExists) CursorToggle (); ! 395: } ! 396: XPixSet (XXwindow, ! 397: start * fontinfo->width + XXInternalBorder, ! 398: cursor_vpos * fontinfo->height+XXInternalBorder, ! 399: fontinfo->width * numcols, ! 400: fontinfo->height, ! 401: back); ! 402: XTmove_cursor (cursor_vpos, start); ! 403: UNBLOCK_INPUT (); ! 404: } ! 405: } ! 406: ! 407: static ! 408: XTreset_terminal_modes () ! 409: { ! 410: #ifdef XDEBUG ! 411: fprintf (stderr, "XTreset_terminal_modes\n"); ! 412: #endif ! 413: XTclear_screen (); ! 414: } ! 415: ! 416: static ! 417: XTclear_screen () ! 418: { ! 419: #ifdef XDEBUG ! 420: fprintf (stderr, "XTclear_screen\n"); ! 421: #endif ! 422: HLmode (0); ! 423: CursorExists = 0; ! 424: ! 425: cursor_hpos = 0; ! 426: cursor_vpos = 0; ! 427: SavedX = 0; ! 428: SavedY = 0; ! 429: VisibleX = 0; ! 430: VisibleY = 0; ! 431: { ! 432: BLOCK_INPUT_DECLARE () ! 433: ! 434: BLOCK_INPUT (); ! 435: XClear (XXwindow); ! 436: CursorToggle (); ! 437: if (!InUpdate) ! 438: XFlush (); ! 439: UNBLOCK_INPUT (); ! 440: } ! 441: } ! 442: ! 443: /* used by dumprectangle which is usually invoked upon ExposeRegion ! 444: * events which come from bit blt's or moving an obscuring opaque window ! 445: */ ! 446: ! 447: static ! 448: dumpchars (current_screen, numcols, tempX, tempY, tempHL) ! 449: register struct matrix *current_screen; ! 450: register int numcols; ! 451: register int tempX, tempY, tempHL; ! 452: { ! 453: if (numcols <= 0) return; ! 454: if (((numcols - 1) + tempX) > screen_width) ! 455: { ! 456: numcols = (screen_width - tempX) + 1; ! 457: } ! 458: if ((tempX < 0) || (tempX >= screen_width) || ! 459: (tempY < 0) || (tempY >= screen_height)) ! 460: { ! 461: return; ! 462: } ! 463: XText (XXwindow, ! 464: (tempX * fontinfo->width+XXInternalBorder), ! 465: (tempY * fontinfo->height+XXInternalBorder), ! 466: ¤t_screen->contents[tempY][tempX], ! 467: numcols, ! 468: fontinfo->id, ! 469: (tempHL ? back : fore), ! 470: (tempHL ? fore : back)); ! 471: } ! 472: ! 473: /* When a line has been changed this function is called. X is so fast ! 474: * that the actual sequence is ignore. Rather, the new version of the ! 475: * line is simply output if this function is invoked while in UpDate. ! 476: * Sometimes writechars can be invoked when not in update if text is to ! 477: * be output at the end of the line. In this case the whole line is not ! 478: * output. Simply the new text at the current cursor position given ! 479: * by VisibleX,Y. The cursor is moved to the end of the new text. ! 480: */ ! 481: static ! 482: writechars (start, end) ! 483: register char *start, *end; ! 484: { ! 485: register int temp_length; ! 486: BLOCK_INPUT_DECLARE () ! 487: ! 488: BLOCK_INPUT (); ! 489: ! 490: if ((cursor_vpos < 0) || (cursor_vpos >= screen_height)) ! 491: { ! 492: UNBLOCK_INPUT (); ! 493: return; ! 494: } ! 495: if (CursorExists) ! 496: { ! 497: CursorToggle (); ! 498: } ! 499: if (InUpdate) ! 500: { ! 501: if (end != start - 1) ! 502: { ! 503: XText (XXwindow, ! 504: (cursor_hpos * fontinfo->width+XXInternalBorder), ! 505: (cursor_vpos * fontinfo->height+XXInternalBorder), ! 506: start, ! 507: end + 1 - start, ! 508: fontinfo->id, ! 509: (CurHL ? back : fore), ! 510: (CurHL ? fore : back)); ! 511: XTmove_cursor (cursor_vpos, cursor_hpos + end - start + 1); ! 512: } ! 513: } ! 514: else ! 515: { ! 516: if ((VisibleX < 0) || (VisibleX >= screen_width)) ! 517: { ! 518: UNBLOCK_INPUT (); ! 519: return; ! 520: } ! 521: if ((VisibleY < 0) || (VisibleY >= screen_height)) ! 522: { ! 523: UNBLOCK_INPUT (); ! 524: return; ! 525: } ! 526: if (((end - start) + VisibleX) >= screen_width) ! 527: { ! 528: end = start + (screen_width - (VisibleX + 1)); ! 529: } ! 530: if (end >= start) ! 531: { ! 532: XText (XXwindow, ! 533: (VisibleX * fontinfo->width+XXInternalBorder), ! 534: (VisibleY * fontinfo->height+XXInternalBorder), ! 535: start, ! 536: ((end - start) + 1), ! 537: fontinfo->id, ! 538: (CurHL ? back : fore), ! 539: (CurHL ? fore : back)); ! 540: VisibleX = VisibleX + (end - start) + 1; ! 541: } ! 542: if (!CursorExists) CursorToggle (); ! 543: } ! 544: UNBLOCK_INPUT (); ! 545: } ! 546: ! 547: ! 548: static ! 549: XToutput_chars (start, len) ! 550: register char *start; ! 551: register int len; ! 552: { ! 553: #ifdef XDEBUG ! 554: fprintf (stderr, "XToutput_chars\n"); ! 555: #endif ! 556: writechars (start, start + len - 1); ! 557: } ! 558: ! 559: /* The following routine is for the deaf or for the pervert who prefers ! 560: * that his terminal flash at him rather than beep at him. ! 561: */ ! 562: ! 563: static int flashedback; ! 564: ! 565: static ! 566: XTflash () ! 567: { ! 568: #ifdef ITIMER_REAL ! 569: struct itimerval itimer; ! 570: ! 571: #ifdef XDEBUG ! 572: fprintf (stderr, "XTflash\n"); ! 573: #endif ! 574: ! 575: stop_polling (); ! 576: signal (SIGALRM, flashback); ! 577: getitimer (ITIMER_REAL, &itimer); ! 578: itimer.it_value.tv_usec += 250000; ! 579: itimer.it_interval.tv_sec = 0; ! 580: itimer.it_interval.tv_usec = 0; ! 581: flashedback = 0; ! 582: setitimer (ITIMER_REAL, &itimer, 0); ! 583: { ! 584: BLOCK_INPUT_DECLARE () ! 585: ! 586: BLOCK_INPUT (); ! 587: XPixFill (XXwindow, 0, 0, screen_width*fontinfo->width+2*XXInternalBorder, ! 588: screen_height * fontinfo->height+2*XXInternalBorder, WhitePixel, ! 589: ClipModeClipped, GXinvert, AllPlanes); ! 590: XFlush (); ! 591: UNBLOCK_INPUT (); ! 592: } ! 593: while (!flashedback) pause (); ! 594: #endif /* have ITIMER_REAL */ ! 595: } ! 596: ! 597: static ! 598: flashback () ! 599: { ! 600: #ifdef ITIMER_REAL ! 601: #ifdef SIGIO ! 602: int mask = sigblock (sigmask (SIGIO) | sigmask (SIGALRM)); ! 603: #else ! 604: int mask = sigblock (sigmask (SIGALRM)); ! 605: #endif ! 606: XPixFill (XXwindow, 0, 0, screen_width * fontinfo->width+2*XXInternalBorder, ! 607: screen_height * fontinfo->height+2*XXInternalBorder, WhitePixel, ! 608: ClipModeClipped, GXinvert, AllPlanes); ! 609: XFlush (); ! 610: flashedback = 1; ! 611: sigsetmask (mask); ! 612: start_polling (); ! 613: #endif /* have ITIMER_REAL */ ! 614: } ! 615: ! 616: /* A kludge to get a bell */ ! 617: ! 618: static ! 619: XTfeep () ! 620: { ! 621: BLOCK_INPUT_DECLARE () ! 622: ! 623: BLOCK_INPUT (); ! 624: #ifdef XDEBUG ! 625: fprintf (stderr, "XTfeep\n"); ! 626: #endif ! 627: XFeep (0); ! 628: UNBLOCK_INPUT (); ! 629: } ! 630: ! 631: /* Artificially creating a cursor is hard, the actual position on the ! 632: * screen (either where it is or last was) is tracked with VisibleX,Y. ! 633: * Gnu Emacs code tends to assume a cursor exists in hardward at cursor_hpos,Y ! 634: * and that output text will appear there. During updates, the cursor is ! 635: * supposed to be blinked out and will only reappear after the update ! 636: * finishes. ! 637: */ ! 638: ! 639: CursorToggle () ! 640: { ! 641: if (!WindowMapped) ! 642: { ! 643: CursorExists = 0; ! 644: return 0; ! 645: } ! 646: if ((VisibleX < 0) || (VisibleX >= screen_width) || ! 647: (VisibleY < 0) || (VisibleY >= screen_height)) ! 648: { /* Current Cursor position trash */ ! 649: /* Not much can be done */ ! 650: XFlush (); ! 651: CursorExists = 0; ! 652: return 0; ! 653: /* Currently the return values are not */ ! 654: /* used, but I could anticipate using */ ! 655: /* them in the future. */ ! 656: } ! 657: ! 658: if (current_screen->enable[VisibleY] && ! 659: (VisibleX < current_screen->used[VisibleY])) ! 660: { ! 661: if (CursorExists) ! 662: { ! 663: XText (XXwindow, ! 664: VisibleX * fontinfo->width+XXInternalBorder, ! 665: VisibleY * fontinfo->height+XXInternalBorder, ! 666: ¤t_screen->contents[VisibleY][VisibleX], 1, ! 667: fontinfo->id, ! 668: fore, back); ! 669: } ! 670: else ! 671: { ! 672: XText (XXwindow, ! 673: VisibleX * fontinfo->width+XXInternalBorder, ! 674: VisibleY * fontinfo->height+XXInternalBorder, ! 675: ¤t_screen->contents[VisibleY][VisibleX], 1, ! 676: fontinfo->id, ! 677: back, curs); ! 678: } ! 679: } ! 680: else if (CursorExists) ! 681: { ! 682: XPixSet (XXwindow, ! 683: VisibleX * fontinfo->width+XXInternalBorder, ! 684: VisibleY * fontinfo->height+XXInternalBorder, ! 685: fontinfo->width, fontinfo->height, back); ! 686: } ! 687: else ! 688: { ! 689: XPixSet (XXwindow, ! 690: VisibleX * fontinfo->width+XXInternalBorder, ! 691: VisibleY * fontinfo->height+XXInternalBorder, ! 692: fontinfo->width, fontinfo->height, curs); ! 693: } ! 694: CursorExists = !CursorExists; ! 695: /* Cursor has either been blinked in */ ! 696: /* or out */ ! 697: if (!InUpdate) ! 698: { ! 699: XFlush (); ! 700: } ! 701: return 1; ! 702: } ! 703: ! 704: /* This routine is used by routines which are called to paint regions */ ! 705: /* designated by ExposeRegion events. If the cursor may be in the exposed */ ! 706: /* region, this routine makes sure it is gone so that dumprectangle can */ ! 707: /* toggle it back into existance if dumprectangle is invoked when not in */ ! 708: /* the midst of a screen update. */ ! 709: static ! 710: ClearCursor () ! 711: { ! 712: BLOCK_INPUT_DECLARE () ! 713: ! 714: BLOCK_INPUT (); ! 715: if (!WindowMapped) ! 716: { ! 717: CursorExists = 0; ! 718: UNBLOCK_INPUT (); ! 719: return; ! 720: } ! 721: if ((VisibleX < 0) || (VisibleX >= screen_width) ! 722: || (VisibleY < 0) || (VisibleY >= screen_height)) ! 723: { /* Current Cursor position trash */ ! 724: /* Not much can be done */ ! 725: CursorExists = 0; ! 726: UNBLOCK_INPUT (); ! 727: return; ! 728: } ! 729: XPixSet (XXwindow, ! 730: VisibleX * fontinfo->width+XXInternalBorder, ! 731: VisibleY * fontinfo->height+XXInternalBorder, ! 732: fontinfo->width, fontinfo->height, ! 733: back); ! 734: CursorExists = 0; ! 735: UNBLOCK_INPUT (); ! 736: } ! 737: ! 738: static ! 739: XTupdate_begin () ! 740: { ! 741: BLOCK_INPUT_DECLARE () ! 742: ! 743: BLOCK_INPUT (); ! 744: #ifdef XDEBUG ! 745: fprintf (stderr, "XTupdate_begin\n"); ! 746: #endif ! 747: ! 748: InUpdate = 1; ! 749: if (CursorExists) ! 750: { ! 751: CursorToggle (); ! 752: } ! 753: SavedX = cursor_hpos; /* The initial"hardware" cursor position is */ ! 754: /* saved because that is where gnu emacs */ ! 755: /* expects the cursor to be at the end of*/ ! 756: /* the update */ ! 757: SavedY = cursor_vpos; ! 758: dumpqueue (); ! 759: UNBLOCK_INPUT (); ! 760: } ! 761: ! 762: ! 763: static ! 764: XTupdate_end () ! 765: { ! 766: BLOCK_INPUT_DECLARE () ! 767: ! 768: BLOCK_INPUT (); ! 769: #ifdef XDEBUG ! 770: fprintf (stderr, "XTupdate_end\n"); ! 771: #endif ! 772: if (CursorExists) ! 773: CursorToggle (); ! 774: InUpdate = 0; ! 775: dumpqueue (); ! 776: XTmove_cursor (SavedY, SavedX); /* XTmove_cursor invokes cursor toggle */ ! 777: UNBLOCK_INPUT (); ! 778: } ! 779: ! 780: /* Used for expose region and expose copy events. Have to get the text ! 781: * back into the newly blank areas. ! 782: */ ! 783: ! 784: dumprectangle (top, left, rows, cols) ! 785: register int top, left, rows, cols; ! 786: { ! 787: register int index; ! 788: int localX, localY, localHL; ! 789: rows += top; ! 790: cols += left; ! 791: top /= fontinfo->height; ! 792: /* Get row and col containing up and */ ! 793: /* left borders of exposed region -- */ ! 794: /* round down here*/ ! 795: left /= fontinfo->width; ! 796: rows += (fontinfo->height - 1); ! 797: cols += (fontinfo->width - 1); ! 798: rows /= fontinfo->height; ! 799: /* Get row and col containing bottom and */ ! 800: /* right borders -- round up here */ ! 801: rows -= top; ! 802: cols /= fontinfo->width; ! 803: cols -= left; ! 804: if (rows < 0) return; ! 805: if (cols < 0) return; ! 806: if (top > (screen_height - 1)) return; ! 807: if (left > (screen_width - 1)) return; ! 808: if ((VisibleX >= left) && (VisibleX < (left + cols)) && ! 809: (VisibleY >= top) && (VisibleY < (top + rows))) ! 810: { ! 811: ClearCursor (); ! 812: } ! 813: ! 814: /* should perhaps be DesiredScreen */ ! 815: /* but PhysScreen is guaranteed to contain*/ ! 816: /* date which was good for every line on */ ! 817: /* screen. For desired screen only for */ ! 818: /* lines which are changing. Emacs does */ ! 819: /* not consider a line within a newly */ ! 820: /* exposed region necessarily to have */ ! 821: /* been changed. Emacs knows nothing */ ! 822: /* about ExposeRegion events.*/ ! 823: for (localY = top, index = 0; ! 824: (index < rows) && (localY < screen_height); ! 825: ++index, ++localY) ! 826: { ! 827: if ((localY < 0) || (localY >= screen_height)) continue; ! 828: if (!current_screen->enable[localY]) continue; ! 829: if ((left + 1) > current_screen->used[localY]) continue; ! 830: localX = left; ! 831: localHL = current_screen->highlight[localY]; ! 832: dumpchars (current_screen, ! 833: min (cols, ! 834: current_screen->used[localY] ! 835: - localX), ! 836: localX, localY, localHL); ! 837: } ! 838: if (!InUpdate && !CursorExists) CursorToggle (); ! 839: /* Routine usually called */ ! 840: /* when not in update */ ! 841: } ! 842: ! 843: /* What sections of the window will be modified from the UpdateDisplay ! 844: * routine is totally under software control. Any line with Y coordinate ! 845: * greater than flexlines will not change during an update. This is really ! 846: * used only during dellines and inslines routines (scraplines and stufflines) ! 847: */ ! 848: static ! 849: XTset_terminal_window (n) ! 850: register int n; ! 851: { ! 852: #ifdef XDEBUG ! 853: fprintf (stderr, "XTset_terminal_window\n"); ! 854: #endif ! 855: if ((n <= 0) || (n > screen_height)) ! 856: flexlines = screen_height; ! 857: else ! 858: flexlines = n; ! 859: } ! 860: ! 861: XTins_del_lines (vpos, n) ! 862: int vpos, n; ! 863: { ! 864: #ifdef XDEBUG ! 865: fprintf (stderr, "XTins_del_lines\n"); ! 866: #endif ! 867: XTmove_cursor (vpos, 0); ! 868: if (n >= 0) stufflines (n); ! 869: else scraplines (-n); ! 870: } ! 871: ! 872: static ! 873: XTinsert_chars (start, len) ! 874: register char *start; ! 875: register int len; ! 876: { ! 877: #ifdef XDEBUG ! 878: fprintf (stderr, "XTinsert_chars\n"); ! 879: #endif ! 880: writechars (start, start + len - 1); ! 881: } ! 882: ! 883: static ! 884: XTdelete_chars (n) ! 885: register int n; ! 886: { ! 887: char *msg = "***Delete Chars Called Outside of Update!!!***"; ! 888: #ifdef XDEBUG ! 889: fprintf (stderr, "XTdelete_chars\n"); ! 890: #endif ! 891: writechars (msg, msg + strlen (msg) - 1); ! 892: } ! 893: ! 894: static ! 895: stufflines (n) ! 896: register int n; ! 897: { ! 898: register int topregion, bottomregion; ! 899: register int length, newtop; ! 900: BLOCK_INPUT_DECLARE () ! 901: ! 902: if (cursor_vpos >= flexlines) ! 903: return; ! 904: ! 905: if (!WindowMapped) ! 906: { ! 907: bitblt = 0; ! 908: return; ! 909: } ! 910: BLOCK_INPUT (); ! 911: if (CursorExists) CursorToggle (); ! 912: dumpqueue (); ! 913: UNBLOCK_INPUT (); ! 914: topregion = cursor_vpos; ! 915: bottomregion = flexlines - (n + 1); ! 916: newtop = cursor_vpos + n; ! 917: length = (bottomregion - topregion) + 1; ! 918: if ((length > 0) && (newtop <= flexlines)) ! 919: { ! 920: BLOCK_INPUT (); ! 921: /* Should already have cleared */ ! 922: /* queue of events associated */ ! 923: /* with old bitblts */ ! 924: XMoveArea (XXwindow, XXInternalBorder, ! 925: topregion * fontinfo->height+XXInternalBorder, ! 926: XXInternalBorder, newtop * fontinfo->height+XXInternalBorder, ! 927: screen_width * fontinfo->width, ! 928: length * fontinfo->height); ! 929: if (WindowMapped) ! 930: bitblt = 1; ! 931: XFlush (); ! 932: UNBLOCK_INPUT (); ! 933: SIGNAL_INPUT_WHILE (bitblt); ! 934: XFlush (); ! 935: } ! 936: newtop = min (newtop, (flexlines - 1)); ! 937: length = newtop - topregion; ! 938: if (length > 0) ! 939: { ! 940: XPixSet (XXwindow, ! 941: XXInternalBorder, ! 942: topregion * fontinfo->height+XXInternalBorder, ! 943: screen_width * fontinfo->width, ! 944: n * fontinfo->height, ! 945: back); ! 946: } ! 947: /* if (!InUpdate) CursorToggle (); */ ! 948: } ! 949: ! 950: static ! 951: scraplines (n) ! 952: register int n; ! 953: { ! 954: BLOCK_INPUT_DECLARE () ! 955: if (!WindowMapped) ! 956: { ! 957: bitblt = 0; ! 958: return; ! 959: } ! 960: ! 961: if (cursor_vpos >= flexlines) ! 962: return; ! 963: BLOCK_INPUT (); ! 964: if (CursorExists) CursorToggle (); ! 965: dumpqueue (); ! 966: if ((cursor_vpos + n) >= flexlines) ! 967: { ! 968: if (flexlines >= (cursor_vpos + 1)) ! 969: { ! 970: XPixSet (XXwindow, ! 971: XXInternalBorder, cursor_vpos * fontinfo->height+XXInternalBorder, ! 972: screen_width * fontinfo->width, ! 973: (flexlines - cursor_vpos) * fontinfo->height, ! 974: back); ! 975: } ! 976: UNBLOCK_INPUT (); ! 977: } ! 978: else ! 979: { ! 980: XMoveArea (XXwindow, ! 981: XXInternalBorder, ! 982: (cursor_vpos + n) * fontinfo->height+XXInternalBorder, ! 983: XXInternalBorder, cursor_vpos * fontinfo->height+XXInternalBorder, ! 984: screen_width * fontinfo->width, ! 985: (flexlines - (cursor_vpos + n)) * fontinfo->height); ! 986: if (WindowMapped) ! 987: bitblt = 1; ! 988: XFlush (); ! 989: UNBLOCK_INPUT (); ! 990: SIGNAL_INPUT_WHILE (bitblt); ! 991: BLOCK_INPUT (); ! 992: XFlush (); ! 993: XPixSet (XXwindow, XXInternalBorder, ! 994: (flexlines - n) * fontinfo->height+XXInternalBorder, ! 995: screen_width * fontinfo->width, ! 996: n * fontinfo->height, back); ! 997: UNBLOCK_INPUT (); ! 998: } ! 999: /* if (!InUpdate) CursorToggle (); */ ! 1000: } ! 1001: ! 1002: /* Substitutes for standard read routine. Under X not interested in individual ! 1003: * bytes but rather individual packets. ! 1004: */ ! 1005: ! 1006: XTread_socket (sd, bufp, numchars) ! 1007: register int sd; ! 1008: register char *bufp; ! 1009: register int numchars; ! 1010: { ! 1011: ! 1012: int count; ! 1013: char *where_mapping; ! 1014: int nbytes; ! 1015: int stuffpending; ! 1016: int temp_width, temp_height; ! 1017: BLOCK_INPUT_DECLARE () ! 1018: /* XKeyPressedEvent event; */ ! 1019: /* typedef struct reply {XEvent event; struct reply *next} Reply; ! 1020: Reply *replies = NULL;*/ ! 1021: ! 1022: BLOCK_INPUT (); ! 1023: count = 0; ! 1024: if (numchars <= 0) ! 1025: { /* To keep from overflowing read buffer */ ! 1026: numchars = 1; ! 1027: --bufp; ! 1028: } ! 1029: #ifdef SIGIO ! 1030: while (bitblt || XPending () != 0) ! 1031: #else ! 1032: #ifndef HAVE_SELECT ! 1033: if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY)) ! 1034: { ! 1035: extern int read_alarm_should_throw; ! 1036: if (CursorExists) ! 1037: xfixscreen (); ! 1038: read_alarm_should_throw = 1; ! 1039: XPeekEvent (&XXEvent); ! 1040: read_alarm_should_throw = 0; ! 1041: } ! 1042: #endif ! 1043: while (XPending () != 0) ! 1044: #endif ! 1045: { ! 1046: /* while there are more events*/ ! 1047: XNextEvent (&XXEvent); ! 1048: switch (XXEvent.type) ! 1049: { ! 1050: /* case X_Reply: ! 1051: { ! 1052: extern char *malloc (); ! 1053: Reply *reply = (Reply *) malloc (sizeof (Reply)); ! 1054: reply->next = replies; ! 1055: reply->event = XXEvent; ! 1056: replies = reply; ! 1057: break; ! 1058: }*/ ! 1059: default: ! 1060: break; ! 1061: case ExposeWindow: ! 1062: if (((XExposeEvent *)&XXEvent)->window == XXIconWindow) ! 1063: { ! 1064: PendingIconExposure = 1; ! 1065: } ! 1066: else ! 1067: PendingExposure = 1;/* No reason to repeat */ ! 1068: /* this if several */ ! 1069: /* ExposeWindow events */ ! 1070: /* come in quick succes-*/ ! 1071: /* ion */ ! 1072: break; ! 1073: case ExposeRegion: ! 1074: if (PendingExposure) ! 1075: { /* Don't bother with */ ! 1076: /* region events when */ ! 1077: /* full window event */ ! 1078: /* is pending */ ! 1079: break; ! 1080: } ! 1081: loadxrepbuffer (&XXEvent, &XXqueue); ! 1082: if (XXqueue.rindex == XXqueue.windex) ! 1083: { ! 1084: PendingExposure = 1; ! 1085: } ! 1086: if ((XXqueue.rindex > XXqueue.mindex) || ! 1087: (XXqueue.windex > XXqueue.mindex) || ! 1088: (XXqueue.rindex < 0) || ! 1089: (XXqueue.windex < 0)) ! 1090: { ! 1091: PendingExposure = 1; ! 1092: } ! 1093: break; ! 1094: case ExposeCopy: /* For ExposeCopy sync */ ! 1095: /* will block all outgoing */ ! 1096: /* requests until this is */ ! 1097: /* decremented */ ! 1098: if (WindowMapped) bitblt = 0; ! 1099: break; ! 1100: case KeyPressed: ! 1101: /* bcopy (XXEvent, event, sizeof (XKeyPressedEvent)); */ ! 1102: where_mapping = XLookupMapping (&XXEvent, &nbytes); ! 1103: /* Nasty fix for arrow keys */ ! 1104: if (!nbytes && IsCursorKey (XXEvent.detail & 0xff)) ! 1105: { ! 1106: switch (XXEvent.detail & 0xff) ! 1107: { ! 1108: case KC_CURSOR_LEFT: ! 1109: where_mapping = "\002"; ! 1110: break; ! 1111: case KC_CURSOR_RIGHT: ! 1112: where_mapping = "\006"; ! 1113: break; ! 1114: case KC_CURSOR_UP: ! 1115: where_mapping = "\020"; ! 1116: break; ! 1117: case KC_CURSOR_DOWN: ! 1118: where_mapping = "\016"; ! 1119: break; ! 1120: } ! 1121: nbytes = 1; ! 1122: } ! 1123: if (numchars - nbytes > 0) ! 1124: { ! 1125: bcopy (where_mapping, bufp, nbytes); ! 1126: bufp += nbytes; ! 1127: count += nbytes; ! 1128: numchars -= nbytes; ! 1129: } ! 1130: /* else ! 1131: { ! 1132: bcopy (where_mapping, bufp, numchars); ! 1133: bufp += numchars; ! 1134: count += numchars; ! 1135: numchars = 0; ! 1136: *(bufp-1) = *(where_mapping + nbytes - 1); ! 1137: }*/ ! 1138: break; ! 1139: case ButtonPressed: ! 1140: case ButtonReleased: ! 1141: switch (spacecheck (Xxrepbuffer.mindex, ! 1142: Xxrepbuffer.rindex, ! 1143: Xxrepbuffer.windex, 0)) ! 1144: { ! 1145: case 0: ! 1146: loadxrepbuffer (&XXEvent, ! 1147: &Xxrepbuffer); ! 1148: if (informflag && (numchars > 1)) ! 1149: { ! 1150: *bufp++ = (char) 'X' & 037; /* C-x */ ! 1151: ++count; ! 1152: --numchars; ! 1153: *bufp++ = (char) 0; /* C-@ */ ! 1154: ++count; ! 1155: --numchars; ! 1156: } ! 1157: break; ! 1158: case -1: ! 1159: break; ! 1160: case -2: ! 1161: default: ! 1162: fixxrepbuffer (); ! 1163: break; ! 1164: } ! 1165: break; ! 1166: } ! 1167: } ! 1168: /* while (replies) { ! 1169: Reply *reply = replies; ! 1170: XPutBackEvent (&reply->event); ! 1171: replies = reply->next; ! 1172: free (reply); ! 1173: }*/ ! 1174: if (count < 0) ! 1175: count = 0; ! 1176: #ifdef HAVE_SELECT ! 1177: if (CursorExists ! 1178: #ifdef O_NDELAY ! 1179: #ifdef F_GETFL ! 1180: && (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY)) ! 1181: #endif ! 1182: #endif ! 1183: ) ! 1184: xfixscreen (); ! 1185: #endif ! 1186: UNBLOCK_INPUT (); ! 1187: return count; ! 1188: } ! 1189: ! 1190: /* refresh bitmap kitchen sink icon */ ! 1191: refreshicon () ! 1192: { ! 1193: BLOCK_INPUT_DECLARE () ! 1194: ! 1195: BLOCK_INPUT (); ! 1196: if (XXIconWindow) ! 1197: XBitmapBitsPut (XXIconWindow, 0, 0, sink_width, sink_height, ! 1198: sink_bits, BlackPixel, WhitePixel, ! 1199: XXIconMask, GXcopy, AllPlanes); ! 1200: XFlush (); ! 1201: UNBLOCK_INPUT (); ! 1202: } ! 1203: ! 1204: XBitmapIcon () ! 1205: { ! 1206: BLOCK_INPUT_DECLARE () ! 1207: ! 1208: BLOCK_INPUT (); ! 1209: if (!IconWindow) ! 1210: { ! 1211: XSetIconWindow (XXwindow,XXIconWindow); ! 1212: XSelectInput (XXIconWindow, ExposeWindow); ! 1213: IconWindow = !IconWindow; ! 1214: } ! 1215: UNBLOCK_INPUT (); ! 1216: } ! 1217: ! 1218: XTextIcon () ! 1219: { ! 1220: BLOCK_INPUT_DECLARE () ! 1221: ! 1222: BLOCK_INPUT (); ! 1223: if (IconWindow) ! 1224: { ! 1225: XClearIconWindow (XXwindow); ! 1226: XSelectInput (XXIconWindow, NoEvent); ! 1227: IconWindow = !IconWindow; ! 1228: } ! 1229: UNBLOCK_INPUT (); ! 1230: } ! 1231: ! 1232: /* Interpreting incoming keycodes. Should have table modifiable as needed ! 1233: * from elisp. ! 1234: */ ! 1235: ! 1236: /* Exit gracefully from gnuemacs, doing an autosave and giving a status. ! 1237: */ ! 1238: ! 1239: XExitGracefully (disp, event) ! 1240: Display *disp; ! 1241: XErrorEvent *event; ! 1242: { ! 1243: XCleanUp (); ! 1244: exit (70); ! 1245: } ! 1246: ! 1247: x_io_error (disp) ! 1248: Display *disp; ! 1249: { ! 1250: XCleanUp (); ! 1251: exit (71); ! 1252: } ! 1253: ! 1254: #if 0 ! 1255: /* This kludge overcomes the failure to handle EAGAIN and EINTR ! 1256: in a certain version of X for 386 running system V. */ ! 1257: ! 1258: x_io_error (disp, a, b, c, nwrite) ! 1259: Display *disp; ! 1260: { ! 1261: extern _XSend (); ! 1262: unsigned int pc = ((unsigned int *)&disp)[-1]; ! 1263: if (pc - (unsigned int)&_XSend - 100 < 100 ! 1264: && (errno == EAGAIN || errno == EINTR)) ! 1265: { ! 1266: /* We were called by `writedata' erroneously. ! 1267: Modify a local variable which `writedata' ! 1268: will subtract from the number of bytes to be written. */ ! 1269: nwrite = 0; ! 1270: return; ! 1271: } ! 1272: abort (); ! 1273: } ! 1274: #endif ! 1275: ! 1276: xfixscreen () ! 1277: { ! 1278: register int temp_width, temp_height; ! 1279: BLOCK_INPUT_DECLARE () ! 1280: /* register int temp_x, temp_y; */ ! 1281: ! 1282: BLOCK_INPUT (); ! 1283: dumpqueue (); ! 1284: /* Check that the connection is in fact open. This works by doing a nop */ ! 1285: /* (well, almost) write operation. If there is an XIOerror or a */ ! 1286: /* SIGPIPE, exit gracefully. This fixes the loop-on-logout bug.*/ ! 1287: /* XIOErrorHandler (XExitGracefully); */ ! 1288: XPixFill (XXwindow, 0, 0, 1, 1, back, ClipModeClipped, GXnoop, AllPlanes); ! 1289: XFlush (); ! 1290: /* XIOErrorHandler (0); */ ! 1291: if (PendingIconExposure) ! 1292: { ! 1293: refreshicon (); ! 1294: PendingIconExposure = 0; ! 1295: } ! 1296: if (PendingExposure) ! 1297: { ! 1298: PendingExposure = 0; ! 1299: ClearCursor (); ! 1300: XXqueue.rindex = 0; ! 1301: XXqueue.windex = 0; ! 1302: XQueryWindow (XXwindow, &windowinfo); /* Dangerous to do */ ! 1303: /* writes here but */ ! 1304: /* otherwise would */ ! 1305: /* have to alter */ ! 1306: /* gnu emacs display */ ! 1307: /* routines to query */ ! 1308: /* when screen garbaged */ ! 1309: temp_width = (windowinfo.width - 2 * XXInternalBorder) / fontinfo->width; ! 1310: temp_height = (windowinfo.height- 2*XXInternalBorder) / fontinfo->height; ! 1311: if (temp_width != screen_width || temp_height != screen_height) ! 1312: change_screen_size (max (5, temp_height), max (10, temp_width), ! 1313: 0, 0, 0); ! 1314: XXxoffset= windowinfo.x; ! 1315: XXyoffset = windowinfo.y; ! 1316: /*if (temp_x != XXxoffset || temp_y != XXyoffset) ! 1317: XSetOffset (temp_x, temp_y);*/ ! 1318: dumprectangle (0, 0, ! 1319: screen_height * fontinfo->height + 2 * XXInternalBorder, ! 1320: screen_width * fontinfo->width + 2 * XXInternalBorder); ! 1321: } ! 1322: if (!InUpdate) ! 1323: if (!CursorExists) ! 1324: CursorToggle (); ! 1325: XFlush (); ! 1326: UNBLOCK_INPUT (); ! 1327: SIGNAL_INPUT (); ! 1328: } ! 1329: ! 1330: x_term_init () ! 1331: { ! 1332: char *vardisplay; ! 1333: char *temp_font; ! 1334: register char *option; ! 1335: extern XTinterrupt_signal (); ! 1336: int reversevideo; ! 1337: Color cdef; ! 1338: char *progname; ! 1339: ! 1340: Fset (intern ("window-system-version"), make_number (10)); ! 1341: ! 1342: vardisplay = (alternate_display ? alternate_display ! 1343: : (char *) egetenv ("DISPLAY")); ! 1344: if (!vardisplay || *vardisplay == '\0') ! 1345: { ! 1346: fprintf (stderr, "DISPLAY environment variable must be set\n"); ! 1347: exit (-200); ! 1348: } ! 1349: ! 1350: XXdisplay = XOpenDisplay (vardisplay); ! 1351: if (XXdisplay == (Display *) 0) ! 1352: { ! 1353: fprintf (stderr, "X server not responding. Check your DISPLAY environment variable.\n"); ! 1354: exit (-200); ! 1355: } ! 1356: x_init_1 (1); ! 1357: Xxrepbuffer.mindex = XREPBUFSIZE - 1; ! 1358: Xxrepbuffer.windex = 0; ! 1359: Xxrepbuffer.rindex = 0; ! 1360: XXqueue.mindex = XREPBUFSIZE - 1; ! 1361: XXqueue.windex = 0; ! 1362: XXqueue.rindex = 0; ! 1363: WindowMapped = 0; ! 1364: baud_rate = 9600; ! 1365: min_padding_speed = 10000; ! 1366: must_write_spaces = 1; ! 1367: informflag = 1; ! 1368: meta_key = 1; ! 1369: visible_bell = 1; ! 1370: #ifdef SIGIO ! 1371: interrupt_input = 1; ! 1372: #endif ! 1373: inverse_video = 1; ! 1374: bitblt = 0; ! 1375: PendingExposure = 0; ! 1376: ! 1377: fix_screen_hook = xfixscreen; ! 1378: clear_screen_hook = XTclear_screen; ! 1379: clear_end_of_line_hook = XTclear_end_of_line; ! 1380: ins_del_lines_hook = XTins_del_lines; ! 1381: change_line_highlight_hook = XTchange_line_highlight; ! 1382: insert_chars_hook = XTinsert_chars; ! 1383: output_chars_hook = XToutput_chars; ! 1384: delete_chars_hook = XTdelete_chars; ! 1385: ring_bell_hook = XTfeep; ! 1386: reset_terminal_modes_hook = XTreset_terminal_modes; ! 1387: set_terminal_modes_hook = XTset_terminal_modes; ! 1388: update_begin_hook = XTupdate_begin; ! 1389: update_end_hook = XTupdate_end; ! 1390: set_terminal_window_hook = XTset_terminal_window; ! 1391: read_socket_hook = XTread_socket; ! 1392: move_cursor_hook = XTmove_cursor; ! 1393: /* raw_move_cursor_hook = XTraw_move_cursor; */ ! 1394: reassert_line_highlight_hook = XTreassert_line_highlight; ! 1395: scroll_region_ok = 1; /* we'll scroll partial screens */ ! 1396: char_ins_del_ok = 0; /* just as fast to write the line */ ! 1397: line_ins_del_ok = 1; /* we'll just blt 'em */ ! 1398: fast_clear_end_of_line = 1; /* X does this well */ ! 1399: memory_below_screen = 0; /* we don't remember what scrolls ! 1400: off the bottom */ ! 1401: dont_calculate_costs = 1; ! 1402: ! 1403: /* New options section */ ! 1404: IconWindow = 0; ! 1405: XXborder = 1; ! 1406: XXInternalBorder = 1; ! 1407: screen_width = 80; ! 1408: screen_height = 66; ! 1409: reversevideo = 0; ! 1410: XXxoffset = 0; ! 1411: XXyoffset = 0; ! 1412: XXdebug = 0; ! 1413: ! 1414: XErrorHandler (XExitGracefully); ! 1415: XIOErrorHandler (x_io_error); ! 1416: ! 1417: progname = "emacs"; ! 1418: if (option = XGetDefault (progname,"ReverseVideo")) ! 1419: if (strcmp (option,"on") == 0) reversevideo = 1; ! 1420: if (option = XGetDefault (progname, "BitmapIcon")) ! 1421: if (strcmp (option, "on") == 0) IconWindow = 1; ! 1422: ! 1423: if (option = XGetDefault (progname,"BorderWidth")) ! 1424: XXborder = atoi (option); ! 1425: if (option = XGetDefault (progname,"InternalBorder")) ! 1426: XXInternalBorder = atoi (option); ! 1427: ! 1428: brdr_color = XGetDefault (progname,"Border"); ! 1429: if (!brdr_color) brdr_color = XGetDefault (progname, "BorderColor"); ! 1430: back_color = XGetDefault (progname,"Background"); ! 1431: fore_color = XGetDefault (progname,"Foreground"); ! 1432: mous_color = XGetDefault (progname,"Mouse"); ! 1433: curs_color = XGetDefault (progname,"Cursor"); ! 1434: ! 1435: temp_font = XGetDefault (progname,"BodyFont"); ! 1436: if (temp_font == 0) temp_font = X_DEFAULT_FONT; ! 1437: XXcurrentfont = (char *) xmalloc (strlen (temp_font) + 1); ! 1438: strcpy (XXcurrentfont, temp_font); ! 1439: ! 1440: /* If user has specified a special keymap for use with Emacs, use it. */ ! 1441: { ! 1442: char *temp = XGetDefault (progname, "KeyMap"); ! 1443: if (temp) XUseKeymap (temp); ! 1444: } ! 1445: ! 1446: if (DisplayCells () > 2) ! 1447: { ! 1448: ! 1449: if (fore_color && XParseColor (fore_color, &cdef) && ! 1450: XGetHardwareColor (&cdef)) ! 1451: fore = cdef.pixel; ! 1452: else ! 1453: { ! 1454: fore_color = "black"; ! 1455: fore = BlackPixel; ! 1456: } ! 1457: ! 1458: if (back_color && XParseColor (back_color, &cdef) && ! 1459: XGetHardwareColor (&cdef)) ! 1460: back = cdef.pixel; ! 1461: else ! 1462: { ! 1463: back_color = "white"; ! 1464: back = WhitePixel; ! 1465: } ! 1466: ! 1467: if (curs_color && XParseColor (curs_color, &cdef) && ! 1468: XGetHardwareColor (&cdef)) ! 1469: curs = cdef.pixel; ! 1470: else ! 1471: { ! 1472: curs_color = "black"; ! 1473: curs = BlackPixel; ! 1474: } ! 1475: ! 1476: if (mous_color && XParseColor (mous_color, &cdef) && ! 1477: XGetHardwareColor (&cdef)) ! 1478: mous = cdef.pixel; ! 1479: else ! 1480: { ! 1481: mous_color = "black"; ! 1482: mous = BlackPixel; ! 1483: } ! 1484: ! 1485: if (brdr_color && XParseColor (brdr_color, &cdef) && ! 1486: XGetHardwareColor (&cdef)) ! 1487: brdr = cdef.pixel; ! 1488: else ! 1489: { ! 1490: brdr_color = "black"; ! 1491: brdr = BlackPixel; ! 1492: } ! 1493: } ! 1494: else ! 1495: { ! 1496: fore_color = curs_color = mous_color = brdr_color = "black"; ! 1497: fore = curs = mous = brdr = BlackPixel; ! 1498: back_color = "white"; ! 1499: back = WhitePixel; ! 1500: } ! 1501: ! 1502: /* ! 1503: if (fore_color && DisplayCells () > 2 && ! 1504: XParseColor (fore_color, &cdef) && XGetHardwareColor (&cdef)) ! 1505: fore = cdef.pixel; ! 1506: else if (fore_color && strcmp (fore_color, "black") == 0) ! 1507: fore = BlackPixel; ! 1508: else if (fore_color && strcmp (fore_color, "white") == 0) ! 1509: fore = WhitePixel; ! 1510: else ! 1511: { ! 1512: fore_color = "black"; ! 1513: fore = BlackPixel; ! 1514: } ! 1515: ! 1516: if (back_color && DisplayCells () > 2 && ! 1517: XParseColor (back_color, &cdef) && XGetHardwareColor (&cdef)) ! 1518: back = cdef.pixel; ! 1519: else if (back_color && strcmp (back_color, "white") == 0) ! 1520: back = WhitePixel; ! 1521: else if (back_color && strcmp (back_color, "black") == 0) ! 1522: back = BlackPixel; ! 1523: else ! 1524: { ! 1525: back_color = "white"; ! 1526: back = WhitePixel; ! 1527: } ! 1528: ! 1529: if (brdr_color && DisplayCells () > 2 && ! 1530: XParseColor (brdr_color, &cdef) && XGetHardwareColor (&cdef)) ! 1531: brdr = cdef.pixel; ! 1532: else if (brdr_color && (!strcmp (brdr_color, "gray") || ! 1533: !strcmp (brdr_color, "grey") || ! 1534: !strcmp (brdr_color, "Gray") || ! 1535: !strcmp (brdr_color, "Grey"))) ! 1536: brdr = BlackPixel; ! 1537: else if (brdr_color && strcmp (brdr_color, "white") == 0) ! 1538: brdr = WhitePixel; ! 1539: else ! 1540: { ! 1541: brdr_color = "black"; ! 1542: brdr = BlackPixel; ! 1543: } ! 1544: ! 1545: if (curs_color && DisplayCells () > 2 && ! 1546: XParseColor (curs_color, &cdef) && XGetHardwareColor (&cdef)) ! 1547: curs = cdef.pixel; ! 1548: else if (curs_color && strcmp (curs_color, "black") == 0) ! 1549: curs = BlackPixel; ! 1550: else if (curs_color && strcmp (curs_color, "white") == 0) ! 1551: curs = WhitePixel; ! 1552: else ! 1553: { ! 1554: curs_color = "black"; ! 1555: curs = BlackPixel; ! 1556: } ! 1557: ! 1558: if (mous_color && DisplayCells () > 2 && ! 1559: XParseColor (mous_color, &cdef) && XGetHardwareColor (&cdef)) ! 1560: mous = cdef.pixel; ! 1561: else if (mous_color && strcmp (mous_color, "black") == 0) ! 1562: mous = BlackPixel; ! 1563: else if (mous_color && strcmp (mous_color, "white") == 0) ! 1564: mous = WhitePixel; ! 1565: else ! 1566: { ! 1567: mous_color = "black"; ! 1568: mous = BlackPixel; ! 1569: } ! 1570: */ ! 1571: ! 1572: XXpid = getpid (); ! 1573: if (XXcurrentfont == (char *) 0) ! 1574: { ! 1575: fprintf (stderr, "Memory allocation failure.\n"); ! 1576: exit (-150); ! 1577: } ! 1578: default_window = "=80x24+0+0"; ! 1579: /* RMS: XTread_socket does not have an interface suitable ! 1580: for being a signal handler. In any case, the SIGIO handler is ! 1581: set up in init_keyboard and X uses the same one as usual. */ ! 1582: /* signal (SIGIO, XTread_socket); */ ! 1583: signal (SIGPIPE, XExitGracefully); ! 1584: XQueryWindow (RootWindow, &rootwindowinfo); ! 1585: strncpy (iconidentity, ICONTAG, MAXICID); ! 1586: fontinfo = XOpenFont (XXcurrentfont); ! 1587: if (fontinfo == (FontInfo *) 0) ! 1588: { ! 1589: fprintf (stderr, "No font\n"); ! 1590: exit (-98); ! 1591: } ! 1592: pixelwidth = screen_width * fontinfo->width + 2 * XXInternalBorder; ! 1593: pixelheight = screen_height * fontinfo->height + 2 * XXInternalBorder; ! 1594: XXwindow = XCreateWindow (RootWindow, ! 1595: XXxoffset /* Absolute horizontal offset */, ! 1596: XXyoffset /* Absolute Vertical offset */, ! 1597: pixelwidth, pixelheight, ! 1598: XXborder, BlackPixmap, WhitePixmap); ! 1599: if (!XXwindow) ! 1600: { ! 1601: fprintf (stderr, "Unable to create window.\n"); ! 1602: exit (-97); ! 1603: } ! 1604: ! 1605: XXIconWindow = XCreateWindow (RootWindow, 0, 0, sink_width, sink_height, ! 1606: 2, WhitePixmap, (Pixmap) NULL); ! 1607: ! 1608: if (!XXIconWindow) ! 1609: { ! 1610: fprintf (stderr, "Unable to create icon window.\n"); ! 1611: fflush (stderr); ! 1612: exit (-97); ! 1613: } ! 1614: XSelectInput (XXIconWindow, NoEvent); ! 1615: XXIconMask = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits); ! 1616: ! 1617: XSelectInput (XXwindow, NoEvent); ! 1618: XSetResizeHint (XXwindow, 2 * XXInternalBorder, 2 * XXInternalBorder, ! 1619: /* fontinfo->width * 1, fontinfo->height * 1, */ ! 1620: fontinfo->width, fontinfo->height); ! 1621: ! 1622: #if defined (BSD) || defined (HPUX) || defined (IBMRTAIX) ! 1623: if (gethostname (&iconidentity[sizeof (ICONTAG) - 1], ! 1624: (MAXICID - 1) - sizeof (ICONTAG))) ! 1625: #endif ! 1626: { ! 1627: iconidentity[sizeof (ICONTAG) - 2] = '\0'; ! 1628: } ! 1629: XStoreName (XXwindow, &iconidentity[0]); ! 1630: ! 1631: EmacsCursor = XCreateCursor (16, 16, MouseCursor, MouseMask, ! 1632: 0, 0, mous, back, GXcopy); ! 1633: XDefineCursor (XXwindow, EmacsCursor); ! 1634: flexlines = screen_height; ! 1635: #if 0 ! 1636: /* Do not call XPopUpWindow here! This is too early. ! 1637: It is supposed ot be called via the term-setup-hook ! 1638: and not until after lisp/term/x-win.el has had a chance ! 1639: to process the user's switches. ! 1640: I am not sure that there are any circumstances under which ! 1641: this should be done here -- RMS. */ ! 1642: XPopUpWindow (); /* This looks at Vxterm */ ! 1643: #endif /* 0 */ ! 1644: if (reversevideo) XFlipColor (); ! 1645: } ! 1646: ! 1647: x_init_1 (unrequest) ! 1648: { ! 1649: #ifdef F_SETOWN ! 1650: extern int old_fcntl_owner; ! 1651: #endif ! 1652: #ifndef USG ! 1653: extern void init_sigio (), request_sigio (), unrequest_sigio (); ! 1654: #endif ! 1655: ! 1656: dup2 (dpyno (), 0); ! 1657: close (dpyno ()); ! 1658: dpyno () = 0; /* Looks a little strange? ! 1659: check the def of the macro; ! 1660: it is a genuine lvalue */ ! 1661: #ifndef USG ! 1662: init_sigio (); ! 1663: request_sigio (); ! 1664: #endif /* USG */ ! 1665: #ifdef F_SETOWN ! 1666: old_fcntl_owner = fcntl (0, F_GETOWN, 0); ! 1667: #ifdef F_SETOWN_SOCK_NEG ! 1668: fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */ ! 1669: #else ! 1670: fcntl (0, F_SETOWN, getpid ()); ! 1671: #endif /* F_SETOWN_SOCK_NEG */ ! 1672: #endif /* F_SETOWN */ ! 1673: #ifndef USG ! 1674: if (unrequest) unrequest_sigio (); ! 1675: #endif ! 1676: } ! 1677: ! 1678: /* Process all queued ExposeRegion events. */ ! 1679: static ! 1680: dumpqueue () ! 1681: { ! 1682: register int i; ! 1683: XExposeRegionEvent r; ! 1684: if ((XXqueue.rindex > XXqueue.mindex) || ! 1685: (XXqueue.windex > XXqueue.mindex) || ! 1686: (XXqueue.rindex < 0) || ! 1687: (XXqueue.windex < 0)) ! 1688: { ! 1689: PendingExposure = 1; ! 1690: } ! 1691: else ! 1692: while (XXqueue.rindex != XXqueue.windex) ! 1693: { ! 1694: if (CursorExists) ! 1695: CursorToggle (); ! 1696: unloadxrepbuffer (&r, &XXqueue); ! 1697: dumprectangle (r.y - XXInternalBorder, r.x - XXInternalBorder, ! 1698: r.height, r.width); ! 1699: } ! 1700: } ! 1701: ! 1702: XSetFlash () ! 1703: { ! 1704: ring_bell_hook = XTflash; ! 1705: } ! 1706: ! 1707: XSetFeep () ! 1708: { ! 1709: ring_bell_hook = XTfeep; ! 1710: } ! 1711: ! 1712: XNewFont (newname) ! 1713: register char *newname; ! 1714: { ! 1715: FontInfo *temp; ! 1716: BLOCK_INPUT_DECLARE () ! 1717: ! 1718: BLOCK_INPUT (); ! 1719: XFlush (); ! 1720: if (XXdebug) ! 1721: fprintf (stderr, "Request id is %d\n", XXdisplay->request); ! 1722: temp = XOpenFont (newname); ! 1723: if (temp == (FontInfo *) 0) ! 1724: { ! 1725: UNBLOCK_INPUT_RESIGNAL (); ! 1726: return -1; ! 1727: } ! 1728: XCloseFont (fontinfo); ! 1729: fontinfo = temp; ! 1730: XSetResizeHint (XXwindow, 2*XXInternalBorder, 2*XXInternalBorder, ! 1731: /* fontinfo->width * 1, fontinfo->height * 1, */ ! 1732: fontinfo->width, fontinfo->height); ! 1733: XSetWindowSize (screen_height, screen_width); ! 1734: UNBLOCK_INPUT_RESIGNAL (); ! 1735: return 0; ! 1736: } ! 1737: ! 1738: XFlipColor () ! 1739: { ! 1740: Pixmap temp; ! 1741: int tempcolor; ! 1742: char *tempname; ! 1743: Cursor temp_curs; ! 1744: BLOCK_INPUT_DECLARE () ! 1745: ! 1746: BLOCK_INPUT (); ! 1747: CursorToggle (); ! 1748: temp = XMakeTile (fore); ! 1749: XChangeBackground (XXwindow, temp); ! 1750: XFreePixmap (temp); ! 1751: temp = XMakeTile (back); ! 1752: if (XXborder) ! 1753: XChangeBorder (XXwindow, temp); ! 1754: XFreePixmap (temp); ! 1755: brdr = back; ! 1756: brdr_color = back_color; ! 1757: tempcolor = fore; ! 1758: fore = back; ! 1759: back = tempcolor; ! 1760: tempname = fore_color ; ! 1761: fore_color = back_color; ! 1762: back_color = tempname; ! 1763: /* XPixFill (XXwindow, 0, 0, screen_width * fontinfo->width, ! 1764: screen_height * fontinfo->height, back, ClipModeClipped, ! 1765: GXcopy, AllPlanes); ! 1766: dumprectangle (0, 0, screen_height * fontinfo->height + 2 * XXInternalBorder, ! 1767: screen_width * fontinfo -> width + 2 * XXInternalBorder);*/ ! 1768: XRedrawDisplay (); ! 1769: if (curs == WhitePixel) ! 1770: { ! 1771: curs = BlackPixel; ! 1772: curs_color = "black"; ! 1773: } ! 1774: else if (curs == BlackPixel) ! 1775: { ! 1776: curs = WhitePixel; ! 1777: curs_color = "white"; ! 1778: } ! 1779: if (mous == WhitePixel) ! 1780: { ! 1781: mous = BlackPixel; ! 1782: mous_color = "black"; ! 1783: } ! 1784: else if (mous == BlackPixel) ! 1785: { ! 1786: mous = WhitePixel; ! 1787: mous_color = "white"; ! 1788: } ! 1789: temp_curs = XCreateCursor (16, 16, MouseCursor, MouseMask, 0, 0, ! 1790: mous, back, GXcopy); ! 1791: XUndefineCursor (XXwindow); ! 1792: XDefineCursor (XXwindow, temp_curs); ! 1793: XFreeCursor (EmacsCursor); ! 1794: bcopy (&temp_curs, &EmacsCursor, sizeof (Cursor)); ! 1795: CursorToggle (); ! 1796: XFlush (); ! 1797: UNBLOCK_INPUT (); ! 1798: } ! 1799: ! 1800: XSetOffset (xoff, yoff) ! 1801: register int xoff, yoff; ! 1802: { ! 1803: BLOCK_INPUT_DECLARE () ! 1804: ! 1805: BLOCK_INPUT (); ! 1806: if (xoff < 0) ! 1807: { ! 1808: XXxoffset = rootwindowinfo.width + (++xoff) - pixelwidth - 4; ! 1809: } ! 1810: else ! 1811: { ! 1812: XXxoffset = xoff; ! 1813: } ! 1814: if (yoff < 0) ! 1815: { ! 1816: XXyoffset ! 1817: = rootwindowinfo.height + (++yoff) - pixelheight - 4; ! 1818: } ! 1819: else ! 1820: { ! 1821: XXyoffset = yoff; ! 1822: } ! 1823: XMoveWindow (XXwindow, XXxoffset, XXyoffset); ! 1824: UNBLOCK_INPUT (); ! 1825: /* XWarpMouse (XXwindow, pixelwidth >> 1, pixelheight >> 1); */ ! 1826: } ! 1827: ! 1828: XSetWindowSize (rows, cols) ! 1829: register int rows, cols; ! 1830: { ! 1831: /* if (rows < 3) rows = 24; ! 1832: if (cols < 1) cols = 80; */ ! 1833: pixelwidth = cols * fontinfo->width + 2 * XXInternalBorder; ! 1834: pixelheight = rows * fontinfo->height + 2 * XXInternalBorder; ! 1835: XChangeWindow (XXwindow, pixelwidth, pixelheight); ! 1836: XFlush (); ! 1837: change_screen_size (rows, cols, 0, 0, 0); ! 1838: PendingExposure = 0; ! 1839: } ! 1840: ! 1841: XPopUpWindow () ! 1842: { ! 1843: BLOCK_INPUT_DECLARE () ! 1844: if (WindowMapped) ! 1845: return; ! 1846: BLOCK_INPUT (); ! 1847: if (!x_edges_specified) ! 1848: Fx_rubber_band (); ! 1849: bitblt = 0; ! 1850: CursorExists = 0; ! 1851: VisibleX = 0; ! 1852: VisibleY = 0; ! 1853: WindowMapped = 1; ! 1854: XMapWindow (XXwindow); ! 1855: dumprectangle (0, 0, ! 1856: screen_height * fontinfo->height + 2 * XXInternalBorder, ! 1857: screen_width * fontinfo->width + 2 * XXInternalBorder); ! 1858: XSelectInput (XXwindow, KeyPressed | ExposeWindow | ButtonPressed ! 1859: | ButtonReleased ! 1860: | ExposeRegion | ExposeCopy); ! 1861: /* XWarpMouse (XXwindow, pixelwidth >> 1, pixelheight >> 1);*/ ! 1862: XTmove_cursor (0, 0); ! 1863: if (IconWindow) ! 1864: { ! 1865: XSetIconWindow (XXwindow,XXIconWindow); ! 1866: XSelectInput (XXIconWindow, ExposeWindow); ! 1867: } ! 1868: else ! 1869: { ! 1870: XClearIconWindow (XXwindow); ! 1871: XSelectInput (XXIconWindow, NoEvent); ! 1872: } ! 1873: /* XRedrawDisplay ();*/ ! 1874: XFlush (); ! 1875: UNBLOCK_INPUT (); ! 1876: } ! 1877: ! 1878: spacecheck (mindex, rindex, windex, minfreespace) ! 1879: register int mindex, rindex, windex, minfreespace; ! 1880: { ! 1881: if ((rindex > mindex) || (windex > mindex)) ! 1882: { ! 1883: /* fprintf (stderr, "Fatal Mouse Buffer Error.\n"); ! 1884: fprintf (stderr, "%d = mindex, %d = rindex, %d = windex\n", ! 1885: mindex, rindex, windex); */ ! 1886: return -2; ! 1887: } ! 1888: if (windex >= rindex) ! 1889: { ! 1890: if ((mindex - (windex - rindex)) > minfreespace) ! 1891: return 0; ! 1892: } ! 1893: else ! 1894: { ! 1895: if (((rindex - windex) - 1) > minfreespace) ! 1896: return 0; ! 1897: } ! 1898: return -1; ! 1899: } ! 1900: ! 1901: loadxrepbuffer (p_xrep, p_buffer) ! 1902: register XEvent *p_xrep; ! 1903: register XREPBUFFER *p_buffer; ! 1904: { ! 1905: p_buffer->xrep[p_buffer->windex] = *p_xrep; ! 1906: if (p_buffer->windex == p_buffer->mindex) ! 1907: p_buffer->windex = 0; ! 1908: else ! 1909: p_buffer->windex++; ! 1910: } ! 1911: ! 1912: unloadxrepbuffer (p_xrep, p_buffer) ! 1913: register XEvent *p_xrep; ! 1914: register XREPBUFFER *p_buffer; ! 1915: { ! 1916: if (p_buffer->windex == p_buffer->rindex) ! 1917: return -1; ! 1918: *p_xrep = p_buffer->xrep[p_buffer->rindex]; ! 1919: if (p_buffer->rindex == p_buffer->mindex) ! 1920: p_buffer->rindex = 0; ! 1921: else ! 1922: p_buffer->rindex++; ! 1923: return 0; ! 1924: } ! 1925: ! 1926: fixxrepbuffer () ! 1927: { ! 1928: Xxrepbuffer.mindex = XREPBUFSIZE - 1; ! 1929: Xxrepbuffer.windex = 0; ! 1930: Xxrepbuffer.rindex = 0; ! 1931: } ! 1932: ! 1933: #endif /* HAVE_X_WINDOWS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.