1: /* X Communication module for terminals which understand the X protocol.
2: Copyright (C) 1985 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU Emacs General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU Emacs, but only under the conditions described in the
15: GNU Emacs General Public License. A copy of this license is
16: supposed to have been given to you along with GNU Emacs so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21: /* Written by Yakim Martillo. */
22:
23: /*
24: * $Source: /u1/third_party/gnuemacs.v17/src/RCS/xterm.c,v $
25: * $Author: rlk $
26: * $Locker: $
27: * $Header: xterm.c,v 1.13 86/02/17 12:24:48 rlk Exp $
28: */
29:
30: #ifndef lint
31: static char *rcsid_TrmXTERM_c = "$Header: xterm.c,v 1.13 86/02/17 12:24:48 rlk Exp $";
32: #endif lint
33:
34: #include "config.h"
35:
36: /* This includes sys/types.h, and that somehow loses
37: if this is not done before the other system files. */
38: #include "xterm.h"
39:
40: #include <sys/time.h>
41: #include <sys/ioctl.h>
42: #include <stdio.h>
43: #include <ctype.h>
44: #include <errno.h>
45: #include <signal.h>
46: #include <strings.h>
47: #include <sys/stat.h>
48:
49: #include "dispextern.h"
50: #include "termhooks.h"
51: #include "termopts.h"
52: #include "termchar.h"
53: #include "sink.h"
54: #include "sinkmask.h"
55: /*#include <X/Xproto.h> */
56:
57: #define min(a,b) ((a)<(b) ? (a) : (b))
58: #define sigunblockx(sig) sigblock (0)
59: #define sigblockx(sig) sigblock (1 << ((sig) - 1))
60: XREPBUFFER Xxrepbuffer;
61: int pixelwidth;
62: int pixelheight;
63: int PendingExposure;
64: int PendingIconExposure;
65: #define MAXICID 80
66: char iconidentity[MAXICID];
67: #define ICONTAG "emacs@"
68: #define METABIT 0x80
69: Window XXIconWindow;
70: Bitmap XXIconMask;
71:
72: char *XXcurrentfont;
73: char *default_window;
74: int informflag;
75: extern struct display_line *DesiredScreen[], *PhysScreen[];
76: extern int initialized;
77: int XXdebug;
78: int XXpid;
79: extern int screen_garbaged;
80: int XXxoffset, XXyoffset;
81: int IconWindow;
82:
83: int WindowMapped;
84: int CurHL;
85:
86: static int flexlines; /* last line affect by dellines or */
87: /* inslines functions */
88: extern int errno;
89: int VisibleX, VisibleY; /* genuine location of cursor on screen */
90: /* if it is there */
91: static int SavedX, SavedY; /* Where the cursor was before update */
92: /* started */
93:
94: int bitblt; /* Used to track bit blt events */
95: int CursorExists; /* during updates cursor is turned off */
96: static int InUpdate; /* many of functions here may be invoked */
97: /* even if no update in progress, when */
98: /* no update is in progress the action */
99: /* can be slightly different */
100: char MouseCursor[33] ="\000\000\002\000\006\000\016\000\036\000\076\000\
101: \176\000\376\000\376\001\076\000\066\000\142\000\140\000\300\000\300\000\000\
102: \000";
103:
104: char MouseMask[33] = "\003\000\007\000\017\000\037\000\077\000\177\000\
105: \377\000\377\001\377\003\377\003\177\000\367\000\363\000\340\001\340\001\
106: \300\000";
107:
108: Display *XXdisplay;
109: FontInfo *fontinfo;
110: Window XXwindow;
111: Cursor EmacsCursor;
112:
113: char *fore_color; /* Variables to store colors */
114: char *back_color;
115: char *brdr_color;
116: char *curs_color;
117: char *mous_color;
118:
119: int fore;
120: int back;
121: int brdr;
122: int curs;
123: int mous;
124:
125: static WindowInfo windowinfo;
126: WindowInfo rootwindowinfo;
127:
128:
129:
130: static XEvent XXEvent; /* as X messages are read in they are */
131: /* stored here */
132: static XREPBUFFER XXqueue;/* Used for storing up ExposeRegion */
133: /* replies, so that the SIGIO inter- */
134: /* rupt serving routines do almost */
135: /* no writes to the X socket */
136: /*int CurHL; /* Current Highlighting actually being */
137: /* being used for bold font right now*/
138:
139: int XXborder;
140:
141:
142: extern Display *XOpenDisplay ();
143: extern Window XCreateWindow ();
144: extern Cursor XDefineCursor ();
145: extern Cursor XCreateCursor ();
146: extern FontInfo *XOpenFont ();
147:
148:
149: /* HLmode -- Changes the GX function for output strings. Could be used to
150: * change font. Check an XText library function call.
151: */
152:
153: static
154: HLmode (new)
155: int new;
156: {
157: CurHL = new;
158: }
159:
160:
161: /* External interface to control of standout mode.
162: Call this when about to modify line at position VPOS
163: and not change whether it is highlighted. */
164:
165: XTreassert_line_highlight (highlight, vpos)
166: int highlight, vpos;
167: {
168: HLmode (highlight);
169: }
170:
171: /* Call this when about to modify line at position VPOS
172: and change whether it is highlighted. */
173:
174: static
175: XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
176: int new_highlight, vpos, first_unused_hpos;
177: {
178: HLmode (new_highlight);
179: XTtopos (vpos, 0);
180: XTclear_end_of_line (0);
181: }
182:
183:
184: /* Used for starting or restarting (after suspension) the X window. Puts the
185: * cursor in a known place, update does not begin with this routine but only
186: * with a call to DoDsp. The mouse cursor is warped into the window and then
187: * the cursor is turned on.
188: */
189:
190:
191:
192: static
193: XTset_terminal_modes ()
194: {
195: int stuffpending;
196: #ifdef XDEBUG
197: fprintf (stderr, "XTset_terminal_modes\n");
198: #endif
199: InUpdate = 0;
200: stuffpending = 0;
201: if (!initialized)
202: {
203: CursorExists = 0;
204: VisibleX = 0;
205: VisibleY = 0;
206: }
207: XTclear_screen ();
208: ioctl (0, FIONREAD, &stuffpending);
209: if (stuffpending)
210: kill (XXpid, SIGIO);
211: }
212:
213: /* XTtopos moves the cursor to the correct location and checks whether an update
214: * is in progress in order to toggle it on.
215: */
216:
217: static
218: XTtopos (row, col)
219: register int row, col;
220: {
221: #ifdef XDEBUG
222: fprintf (stderr, "XTtopos\n");
223: #endif
224: cursX = col;
225: cursY = row;
226: if (InUpdate)
227: {
228: if (CursorExists)
229: {
230: CursorToggle ();
231: }
232: return; /* Generally, XTtopos will be invoked */
233: /* when InUpdate with !CursorExists */
234: /* so that wasteful XFlush is not called */
235: }
236: if ((row == VisibleY) && (col == VisibleX))
237: {
238: if (!CursorExists)
239: {
240: CursorToggle ();
241: }
242: XFlush ();
243: return;
244: }
245: if (CursorExists) CursorToggle ();
246: VisibleX = col;
247: VisibleY = row;
248: if (!CursorExists) CursorToggle ();
249: XFlush ();
250: }
251:
252: /* Used to get the terminal back to a known state after resets. Usually
253: * used when restarting suspended or waiting emacs
254: */
255:
256: static
257: cleanup ()
258: {
259: inverse_video = 0;
260: HLmode (0);
261: }
262:
263: /* wipes out numcols columns starting a current column on the current line */
264:
265: static
266: XTclear_end_of_line (first_blank)
267: register int first_blank;
268: {
269: register int numcols;
270:
271: #ifdef XDEBUG
272: fprintf (stderr, "XTclear_end_of_line\n");
273:
274: #endif
275: if (cursY < 0 || cursY >= screen_height)
276: return;
277: if (first_blank >= screen_width)
278: return;
279:
280: if (first_blank < 0)
281: first_blank = 0;
282: numcols = screen_width - first_blank;
283: if (cursY == VisibleY && VisibleX >= first_blank)
284: {
285: if (CursorExists) CursorToggle ();
286: }
287: XPixSet (XXwindow,
288: first_blank * fontinfo->width,
289: cursY * fontinfo->height,
290: fontinfo->width * numcols,
291: fontinfo->height,
292: back);
293: XTtopos (cursY, first_blank);
294: }
295:
296: static
297: XTreset_terminal_modes ()
298: {
299: #ifdef XDEBUG
300: fprintf (stderr, "XTreset_terminal_modes\n");
301: #endif
302: XTclear_screen ();
303: }
304:
305: static
306: XTclear_screen ()
307: {
308: #ifdef XDEBUG
309: fprintf (stderr, "XTclear_screen\n");
310: #endif
311: HLmode (0);
312: CursorExists = 0;
313:
314: cursX = 0;
315: cursY = 0;
316: SavedX = 0;
317: SavedY = 0;
318: VisibleX = 0;
319: VisibleY = 0;
320: XClear (XXwindow);
321: CursorToggle ();
322: if (!InUpdate)
323: XFlush ();
324: }
325:
326: /* used by dumprectangle which is usually invoked upon ExposeRegion
327: * events which come from bit blt's or moving an obscuring opaque window
328: */
329:
330: static
331: dumpchars (ActiveScreen, numcols, tempX, tempY, tempHL)
332: register struct display_line **ActiveScreen;
333: register int numcols;
334: register int tempX, tempY, tempHL;
335: {
336: if (numcols <= 0) return;
337: if (((numcols - 1) + tempX) > screen_width)
338: {
339: numcols = (screen_width - tempX) + 1;
340: }
341: if ((tempX < 0) || (tempX >= screen_width) ||
342: (tempY < 0) || (tempY >= screen_height))
343: {
344: return;
345: }
346: XText (XXwindow,
347: (tempX * fontinfo->width),
348: (tempY * fontinfo->height),
349: &ActiveScreen[tempY + 1]->body[tempX],
350: numcols,
351: fontinfo->id,
352: (tempHL ? back : fore),
353: (tempHL ? fore : back));
354: }
355:
356: /* When a line has been changed this function is called. X is so fast
357: * that the actual sequence is ignore. Rather, the new version of the
358: * line is simply output if this function is invoked while in UpDate.
359: * Sometimes writechars can be invoked when not in update if text is to
360: * be output at the end of the line. In this case the whole line is not
361: * output. Simply the new text at the current cursor position given
362: * by VisibleX,Y. The cursor is moved to the end of the new text.
363: */
364: static
365: writechars (start, end)
366: register char *start, *end;
367: {
368: register int temp_length;
369:
370: if ((cursY < 0) || (cursY >= screen_height))
371: {
372: return;
373: }
374: if (CursorExists)
375: {
376: CursorToggle ();
377: }
378: if (InUpdate)
379: {
380: if (DesiredScreen && DesiredScreen[cursY + 1])
381: {
382: temp_length = DesiredScreen[cursY + 1]->length;
383: }
384: else
385: temp_length = 0;
386: if (temp_length > 0)
387: {
388: XText (XXwindow,
389: 0,
390: (cursY * fontinfo->height),
391: &DesiredScreen[cursY + 1]->body[0],
392: temp_length,
393: fontinfo->id,
394: (CurHL ? back : fore),
395: (CurHL ? fore : back));
396: if (temp_length < screen_width)
397: {
398: XTclear_end_of_line (temp_length);
399: }
400: XTtopos (cursY, temp_length);
401: }
402: else
403: {
404: XTclear_end_of_line (0);
405: XTtopos (cursY, 0);
406: }
407: }
408: else
409: {
410: if ((VisibleX < 0) || (VisibleX >= screen_width))
411: {
412: return;
413: }
414: if ((VisibleY < 0) || (VisibleY >= screen_height))
415: {
416: return;
417: }
418: if (((end - start) + VisibleX) >= screen_width)
419: {
420: end = start + (screen_width - (VisibleX + 1));
421: }
422: if(end >= start)
423: {
424: XText (XXwindow,
425: (VisibleX * fontinfo->width),
426: (VisibleY * fontinfo->height),
427: start,
428: ((end - start) + 1),
429: fontinfo->id,
430: (CurHL ? back : fore),
431: (CurHL ? fore : back));
432: VisibleX = VisibleX + (end - start) + 1;
433: }
434: if (!CursorExists) CursorToggle ();
435: }
436: }
437:
438:
439: static
440: XTwrite_chars (start, len)
441: register char *start;
442: register int len;
443: {
444: #ifdef XDEBUG
445: fprintf (stderr, "XTwrite_chars\n");
446: #endif
447: writechars (start, start + len - 1);
448: }
449:
450: /* The following routine is for the deaf or for the pervert who prefers
451: * that his terminal flashes at him rather than beep at him.
452: */
453:
454: static int flashedback;
455:
456: static
457: XTflash ()
458: {
459: struct itimerval itimer;
460: extern int flashback ();
461:
462: #ifdef XDEBUG
463: fprintf (stderr, "XTflash\n");
464: #endif
465:
466: signal (SIGALRM, flashback);
467: getitimer (ITIMER_REAL, &itimer);
468: itimer.it_value.tv_usec += 250000;
469: itimer.it_interval.tv_sec = 0;
470: itimer.it_interval.tv_usec = 0;
471: flashedback = 0;
472: setitimer (ITIMER_REAL, &itimer, 0);
473: XPixFill (XXwindow, 0, 0, screen_width * fontinfo->width,
474: screen_height * fontinfo->height, WhitePixel, ClipModeClipped,
475: GXinvert, AllPlanes);
476: XFlush ();
477: while (!flashedback) pause ();
478: }
479:
480: static
481: flashback ()
482: {
483: signal (SIGALRM, SIG_IGN);
484: XPixFill (XXwindow, 0, 0, screen_width * fontinfo->width,
485: screen_height * fontinfo->height, WhitePixel, ClipModeClipped,
486: GXinvert, AllPlanes);
487: XFlush ();
488: flashedback = 1;
489: }
490:
491: /* A kludge to get a bell */
492:
493: static
494: XTfeep ()
495: {
496: #ifdef XDEBUG
497: fprintf (stderr, "XTfeep\n");
498: #endif
499: XFeep (0);
500: }
501:
502: /* Artificially creating a cursor is hard, the actual position on the
503: * screen (either where it is or last was) is tracked with VisibleX,Y.
504: * Gnu Emacs code tends to assume a cursor exists in hardward at cursX,Y
505: * and that output text will appear there. During updates, the cursor is
506: * supposed to be blinked out and will only reappear after the update
507: * finishes.
508: */
509:
510: CursorToggle ()
511: {
512: register struct display_line **ActiveScreen;
513: if (!WindowMapped)
514: {
515: CursorExists = 0;
516: return 0;
517: }
518: if ((VisibleX < 0) || (VisibleX >= screen_width) ||
519: (VisibleY < 0) || (VisibleY >= screen_height))
520: { /* Current Cursor position trash */
521: /* Not much can be done */
522: XFlush ();
523: CursorExists = 0;
524: return 0; /* Currently the return values are not */
525: /* used, but I could anticipate using */
526: /* them in the future. */
527: }
528: /* if(InUpdate && DesiredScreen)
529: ActiveScreen = DesiredScreen;
530: else*/
531: ActiveScreen = PhysScreen;
532: if (ActiveScreen && ActiveScreen[VisibleY + 1] &&
533: (VisibleX < ActiveScreen[VisibleY + 1]->length))
534: {
535: if (CursorExists)
536: {
537: XText (XXwindow,
538: VisibleX * fontinfo->width,
539: VisibleY * fontinfo->height,
540: &ActiveScreen[VisibleY + 1]->body[VisibleX], 1,
541: fontinfo->id,
542: fore, back);
543: }
544: else
545: {
546: XText (XXwindow,
547: VisibleX * fontinfo->width,
548: VisibleY * fontinfo->height,
549: &ActiveScreen[VisibleY + 1]->body[VisibleX], 1,
550: fontinfo->id,
551: back, curs);
552: }
553: }
554: else if (CursorExists)
555: {
556: XPixSet (XXwindow,
557: VisibleX * fontinfo->width,
558: VisibleY * fontinfo->height,
559: fontinfo->width, fontinfo->height, back);
560: }
561: else
562: {
563: XPixSet (XXwindow,
564: VisibleX * fontinfo->width,
565: VisibleY * fontinfo->height,
566: fontinfo->width, fontinfo->height, curs);
567: }
568: CursorExists = !CursorExists;/* Cursor has either been blinked in */
569: /* or out */
570: if (!InUpdate)
571: {
572: XFlush ();
573: }
574: return 1;
575: }
576:
577: /* This routine is used by routines which are called to paint regions */
578: /* designated by ExposeRegion events. If the cursor may be in the exposed */
579: /* region, this routine makes sure it is gone so that dumprectangle can */
580: /* toggle it back into existance if dumprectangle is invoked when not in */
581: /* the midst of a screen update. */
582: static
583: ClearCursor ()
584: {
585: if (!WindowMapped)
586: {
587: CursorExists = 0;
588: return;
589: }
590: if ((VisibleX < 0) || (VisibleX >= screen_width)
591: || (VisibleY < 0) || (VisibleY >= screen_height))
592: { /* Current Cursor position trash */
593: /* Not much can be done */
594: CursorExists = 0;
595: return;
596: }
597: XPixSet (XXwindow,
598: VisibleX * fontinfo->width,
599: VisibleY * fontinfo->height,
600: fontinfo->width, fontinfo->height,
601: back);
602: CursorExists = 0;
603: }
604:
605: static
606: XTupdate_begin ()
607: {
608: #ifdef XDEBUG
609: fprintf (stderr, "XTupdate_begin\n");
610: #endif
611:
612: InUpdate = 1;
613: if (CursorExists)
614: {
615: CursorToggle ();
616: }
617: SavedX = cursX; /* The initial"hardware" cursor position is */
618: /* saved because that is where gnu emacs */
619: /* expects the cursor to be at the end of*/
620: /* the update */
621: SavedY = cursY;
622: dumpqueue();
623: }
624:
625:
626: static
627: XTupdate_end ()
628: {
629: #ifdef XDEBUG
630: fprintf (stderr, "XTupdate_end\n");
631: #endif
632: if (CursorExists)
633: CursorToggle ();
634: InUpdate = 0;
635: dumpqueue ();
636: XTtopos (SavedY, SavedX); /* XTtopos invokes cursor toggle */
637: }
638:
639: /* Used for expose region and expose copy events. Have to get the text
640: * back into the newly blank areas.
641: */
642:
643: dumprectangle (top, left, rows, cols)
644: register int top, left, rows, cols;
645: {
646: register struct display_line **ActiveScreen;
647: register int index;
648: int localX, localY, localHL;
649: rows += top;
650: cols += left;
651: top /= fontinfo->height; /* Get row and col containing up and */
652: /* left borders of exposed region -- */
653: /* round down here*/
654: left /= fontinfo->width;
655: rows += (fontinfo->height - 1);
656: cols += (fontinfo->width - 1);
657: rows /= fontinfo->height;/* Get row and col containing bottom and */
658: /* right borders -- round up here */
659: rows -= top;
660: cols /= fontinfo->width;
661: cols -= left;
662: if (rows < 0) return;
663: if (cols < 0) return;
664: if (top > (screen_height - 1)) return;
665: if (left > (screen_width - 1)) return;
666: if ((VisibleX >= left) && (VisibleX < (left + cols)) &&
667: (VisibleY >= top) && (VisibleY < (top + rows)))
668: {
669: ClearCursor ();
670: }
671: if (InUpdate && DesiredScreen)
672: ActiveScreen = PhysScreen;
673: else if (PhysScreen)
674: ActiveScreen = PhysScreen;/* When cue is dumped in update this */
675: else
676: return;
677: /* should perhaps be DesiredScreen */
678: /* but PhysScreen is guaranteed to contain*/
679: /* date which was good for every line on */
680: /* screen. For desired screen only for */
681: /* lines which are changing. Emacs does */
682: /* not consider a line within a newly */
683: /* exposed region necessarily to have */
684: /* been changed. Emacs knows nothing */
685: /* about ExposeRegion events.*/
686: for (localY = top, index = 0;
687: (index < rows) && (localY < screen_height);
688: ++index, ++localY)
689: {
690: if ((localY < 0) || (localY >= screen_height)) continue;
691: if (!ActiveScreen[localY + 1]) continue;
692: if ((left + 1) > ActiveScreen[localY + 1]->length) continue;
693: localX = left;
694: localHL = ActiveScreen[localY + 1]->highlighted;
695: dumpchars (ActiveScreen,
696: min (cols,
697: ActiveScreen[localY + 1]->length
698: - localX),
699: localX, localY, localHL);
700: }
701: if (!InUpdate && !CursorExists) CursorToggle ();
702: /* Routine usually called */
703: /* when not in update */
704: }
705:
706: /* What sections of the window will be modified from the UpdateDisplay
707: * routine is totally under software control. Any line with Y coordinate
708: * greater than flexlines will not change during an update. This is really
709: * used only during dellines and inslines routines (scraplines and stufflines)
710: */
711: static
712: XTset_terminal_window (n)
713: register int n;
714: {
715: #ifdef XDEBUG
716: fprintf (stderr, "XTset_terminal_window\n");
717: #endif
718: if ((n <= 0) || (n > screen_height))
719: flexlines = screen_height;
720: else
721: flexlines = n;
722: }
723:
724: XTins_del_lines (vpos, n)
725: int vpos, n;
726: {
727: #ifdef XDEBUG
728: fprintf (stderr, "XTins_del_lines\n");
729: #endif
730: XTtopos (vpos, 0);
731: if (n >= 0) stufflines (n);
732: else scraplines (-n);
733:
734: }
735:
736: static
737: XTinsert_chars (start, len)
738: register char *start;
739: register int len;
740: {
741: #ifdef XDEBUG
742: fprintf (stderr, "XTinsert_chars\n");
743: #endif
744: writechars (start, start + len - 1);
745: }
746:
747: static
748: XTdelete_chars (n)
749: register int n;
750: {
751: char *msg = "***Delete Chars Called Outside of Update!!!***";
752: #ifdef XDEBUG
753: fprintf (stderr, "XTdelete_chars\n");
754: #endif
755: writechars (msg, msg + strlen (msg) - 1);
756: }
757:
758: static
759: stufflines (n)
760: register int n;
761: {
762: register int topregion, bottomregion;
763: register int length, newtop;
764:
765: if (cursY >= flexlines)
766: return;
767:
768: if (!WindowMapped)
769: {
770: bitblt = 0;
771: return;
772: }
773: if (CursorExists) CursorToggle ();
774: dumpqueue ();
775: topregion = cursY;
776: bottomregion = flexlines - (n + 1);
777: newtop = cursY + n;
778: length = (bottomregion - topregion) + 1;
779: if ((length > 0) && (newtop <= flexlines))
780: {
781: /* Should already have cleared */
782: /* queue of events associated */
783: /* with old bitblts */
784: XMoveArea (XXwindow, 0,
785: topregion * fontinfo->height,
786: 0, newtop * fontinfo->height,
787: screen_width * fontinfo->width,
788: length * fontinfo->height);
789: if (WindowMapped)
790: bitblt = 1;
791: request_sigio ();
792: XFlush ();
793: while (bitblt)
794: {
795: kill (XXpid, SIGIO);
796: }
797: unrequest_sigio ();
798: XFlush ();
799: }
800: newtop = min (newtop, (flexlines - 1));
801: length = newtop - topregion;
802: if (length > 0)
803: {
804: XPixSet (XXwindow,
805: 0,
806: topregion * fontinfo->height,
807: screen_width * fontinfo->width,
808: n * fontinfo->height,
809: back);
810: }
811: /* if (!InUpdate) CursorToggle (); */
812: }
813:
814: static
815: scraplines (n)
816: register int n;
817: {
818: if (!WindowMapped)
819: {
820: bitblt = 0;
821: return;
822: }
823:
824: if (cursY >= flexlines)
825: return;
826: if (CursorExists) CursorToggle ();
827: dumpqueue ();
828: if ((cursY + n) >= flexlines)
829: {
830: if (flexlines >= (cursY + 1))
831: {
832: XPixSet (XXwindow,
833: 0, cursY * fontinfo->height,
834: screen_width * fontinfo->width,
835: (flexlines - cursY) * fontinfo->height,
836: back);
837: }
838: }
839: else
840: {
841: XMoveArea (XXwindow,
842: 0, (cursY + n) * fontinfo->height,
843: 0, cursY * fontinfo->height,
844: screen_width * fontinfo->width,
845: (flexlines - (cursY + n)) * fontinfo->height);
846: if (WindowMapped)
847: bitblt = 1;
848: request_sigio ();
849: XFlush ();
850: while (bitblt)
851: {
852: kill (XXpid, SIGIO);
853: }
854: unrequest_sigio ();
855: XFlush ();
856: XPixSet (XXwindow, 0, (flexlines - n) * fontinfo->height,
857: screen_width * fontinfo->width,
858: n * fontinfo->height, back);
859: }
860: /* if (!InUpdate) CursorToggle (); */
861: }
862:
863: /* Substitutes for standard read routine. Under X not interested in individual
864: * bytes but rather individual packets.
865: */
866:
867: XTread_socket (sd, bufp, numchars)
868: register int sd;
869: register char *bufp;
870: register int numchars;
871: {
872:
873: int count;
874: int stuffpending;
875: int temp_width, temp_height;
876: /* typedef struct reply {XEvent event; struct reply *next} Reply;
877: Reply *replies = NULL;*/
878:
879: count = 0;
880: if (numchars <= 0)
881: { /* To keep from overflowing read buffer */
882: numchars = 1;
883: --bufp;
884: }
885: while (bitblt || XPending () != 0)
886: {
887: /* while there are more events*/
888: XNextEvent (&XXEvent);
889: switch (XXEvent.type)
890: {
891: /* case X_Reply:
892: {
893: extern char *malloc();
894: Reply *reply = (Reply *) malloc (sizeof (Reply));
895: reply->next = replies;
896: reply->event = XXEvent;
897: replies = reply;
898: break;
899: }*/
900: default:
901: break;
902: case ExposeWindow:
903: if (((XExposeEvent *)&XXEvent)->window == XXIconWindow)
904: {
905: PendingIconExposure = 1;
906: }
907: else
908: PendingExposure = 1;/* No reason to repeat */
909: /* this if several */
910: /* ExposeWindow events */
911: /* come in quick succes-*/
912: /* ion */
913: break;
914: case ExposeRegion:
915: if (PendingExposure)
916: { /* Don't bother with */
917: /* region events when */
918: /* full window event */
919: /* is pending */
920: break;
921: }
922: loadxrepbuffer (&XXEvent, &XXqueue);
923: if (XXqueue.rindex == XXqueue.windex)
924: {
925: PendingExposure = 1;
926: }
927: if ((XXqueue.rindex > XXqueue.mindex) ||
928: (XXqueue.windex > XXqueue.mindex) ||
929: (XXqueue.rindex < 0) ||
930: (XXqueue.windex < 0))
931: {
932: PendingExposure = 1;
933: }
934: break;
935: case ExposeCopy: /* For ExposeCopy sync */
936: /* will block all outgoing */
937: /* requests until this is */
938: /* decremented */
939: if (WindowMapped) bitblt = 0;
940: break;
941: case KeyPressed:
942: if (Input (((XKeyPressedEvent *) &XXEvent)->detail, bufp))
943: {
944: ++bufp;
945: ++count;
946: --numchars;
947: }
948: break;
949: case ButtonPressed:
950: switch (spacecheck (Xxrepbuffer.mindex,
951: Xxrepbuffer.rindex,
952: Xxrepbuffer.windex, 0))
953: {
954: case 0:
955: loadxrepbuffer (&XXEvent,
956: &Xxrepbuffer);
957: if (informflag)
958: {
959: *bufp++ = (char) 003; /* C-c */
960: ++count;
961: --numchars;
962: *bufp++ = (char) '\r'; /* C-m */
963: ++count;
964: --numchars;
965: }
966: break;
967: case -1:
968: break;
969: case -2:
970: default:
971: fixxrepbuffer ();
972: break;
973: }
974: break;
975: }
976: }
977: /* while (replies) {
978: Reply *reply = replies;
979: XPutBackEvent (&reply->event);
980: replies = reply->next;
981: free (reply);
982: }*/
983: if (count < 0)
984: count = 0;
985: if (CursorExists)
986: xfixscreen ();
987: return count;
988: }
989:
990: /* refresh bitmap kitchen sink icon */
991: refreshicon ()
992: {
993: if (XXIconWindow)
994: XBitmapBitsPut (XXIconWindow, 0, 0, sink_width, sink_height,
995: sink_bits, BlackPixel, WhitePixel,
996: XXIconMask, GXcopy, AllPlanes);
997: XFlush ();
998: }
999:
1000: XBitmapIcon ()
1001: {
1002: if (!IconWindow)
1003: {
1004: XSetIconWindow (XXwindow,XXIconWindow);
1005: XSelectInput (XXIconWindow, ExposeWindow);
1006: IconWindow = !IconWindow;
1007: }
1008: }
1009:
1010: XTextIcon ()
1011: {
1012: if (IconWindow)
1013: {
1014: XClearIconWindow (XXwindow);
1015: XSelectInput (XXIconWindow, NoEvent);
1016: IconWindow = !IconWindow;
1017: }
1018: }
1019:
1020: /* Interpreting incoming keycodes. Should have table modifiable as needed
1021: * from elisp.
1022: */
1023:
1024: /* Exit gracefully from gnuemacs, doing an autosave and giving a status.
1025: */
1026:
1027: XExitGracefully ()
1028: {
1029: XAutoSave();
1030: exit(70);
1031: }
1032:
1033: xfixscreen ()
1034: {
1035: register int temp_width, temp_height;
1036: register int (*func) ();
1037: register int temp_x, temp_y;
1038: dumpqueue ();
1039: func = signal (SIGIO, SIG_IGN);
1040: /* Check that the connection is in fact open. This works by doing a nop */
1041: /* (well, almost) write operation. If there is an XIOerror or a */
1042: /* SIGPIPE, exit gracefully. This fixes the loop-on-logout bug.*/
1043: XIOErrorHandler (XExitGracefully);
1044: CursorToggle();
1045: CursorToggle();
1046: XFlush ();
1047: XIOErrorHandler (0);
1048: if (PendingIconExposure)
1049: {
1050: refreshicon ();
1051: PendingIconExposure = 0;
1052: }
1053: if (PendingExposure)
1054: {
1055: PendingExposure = 0;
1056: ClearCursor ();
1057: XXqueue.rindex = 0;
1058: XXqueue.windex = 0;
1059: XQueryWindow (XXwindow, &windowinfo); /* Dangerous to do */
1060: /* writes here but */
1061: /* otherwise would */
1062: /* have to alter */
1063: /* gnu emacs display */
1064: /* routines to query */
1065: /* when screen garbaged */
1066: temp_width = (windowinfo.width / fontinfo->width);
1067: temp_height = (windowinfo.height / fontinfo->height);
1068: if (temp_width != screen_width || temp_height != screen_height)
1069: change_screen_size (temp_height, temp_width);
1070: temp_x = windowinfo.x;
1071: temp_y = windowinfo.y;
1072: if (temp_x != XXxoffset || temp_y != XXyoffset)
1073: XSetOffset (temp_x, temp_y);
1074: dumprectangle (0, 0, screen_height * fontinfo->height,
1075: screen_width * fontinfo->width);
1076: }
1077: if (!InUpdate)
1078: if (!CursorExists)
1079: CursorToggle ();
1080: (void) signal (SIGIO, func);
1081: kill (XXpid, SIGIO);
1082: }
1083:
1084:
1085: static
1086: Input (keycode, buffer)
1087: register int keycode;
1088: register char *buffer;
1089: {
1090: register short c;
1091: register int offset;
1092: extern KeyMapEntry StdMap[];
1093: offset = KeyState (keycode); /* set SHIFT, CONTROL, META */
1094: c = StdMap [keycode & ValueMask] [offset];
1095: if ((keycode & ShiftLockMask) && (c >= 'a') && (c <= 'z'))
1096: {
1097: c += 'A' - 'a';
1098: }
1099: keycode &= ValueMask; /* no longer need shift bits for anything */
1100: if (! (c & ~377))
1101: {
1102: *buffer = c;
1103: return 1;
1104: }
1105: switch (c)
1106: {
1107: /* case '\007':
1108: kill(XXpid, SIGINT);
1109: break;*/
1110: case KEYPAD:
1111: case CURSOR:
1112: switch (keycode & ValueMask)
1113: {
1114: case 0247: /* left-arrow maps to C-B */
1115: c = 002 | ((keycode & MetaMask) ? METABIT : 0);
1116: *buffer = c;
1117: return(1);
1118: case 0250: /* right-arrow maps to C-F */
1119: c = 006 | ((keycode & MetaMask) ? METABIT : 0);
1120: *buffer = c;
1121: return(1);
1122: case 0252: /* up-arrow maps to C-P */
1123: c = 020 | ((keycode & MetaMask) ? METABIT : 0);
1124: *buffer = c;
1125: return(1);
1126: case 0251: /* down-arrow maps to C-N */
1127: c = 016 | ((keycode & MetaMask) ? METABIT : 0);
1128: *buffer = c;
1129: return(1);
1130: default:
1131: return(0);
1132: }
1133: case PFX:
1134: case (short) -1:
1135: case SHFT:
1136: case CNTL:
1137: case SYMBOL:
1138: case LOCK:
1139: case FUNC1:
1140: case FUNC2:
1141: case FUNC3:
1142: case FUNC4:
1143: case FUNC5:
1144: case FUNC6:
1145: case FUNC7:
1146: case FUNC8:
1147: case FUNC9:
1148: case FUNC10:
1149: case FUNC11:
1150: case FUNC12:
1151: case FUNC13:
1152: case FUNC14:
1153: case FUNC15:
1154: case FUNC16:
1155: case FUNC17:
1156: case FUNC18:
1157: case FUNC19:
1158: case FUNC20:
1159: case E1:
1160: case E2:
1161: case E3:
1162: case E4:
1163: case E5:
1164: case E6:
1165: return 0;
1166: default:
1167: *buffer = c;
1168: return 1;
1169: }
1170: }
1171:
1172:
1173: x_term_init ()
1174: {
1175: register char *vardisplay;
1176: register char *colonpointer;
1177: register int status;
1178: extern char *getenv ();
1179: register int scratchindex;
1180: extern XTinterrupt_signal ();
1181: extern char *malloc ();
1182:
1183: vardisplay = getenv ("DISPLAY");
1184: if (!vardisplay)
1185: {
1186: fprintf (stderr, "DISPLAY environment variable must be set\n");
1187: exit (-200);
1188: }
1189: XXdisplay = XOpenDisplay (vardisplay);
1190: if (XXdisplay == (Display *) 0)
1191: {
1192: fprintf (stderr, "No X.\n");
1193: exit (-99);
1194: }
1195: dup2 (dpyno (), 0);
1196: close (dpyno ());
1197: dpyno () = 0; /* Looks a little strange? */
1198: /* check the def of the */
1199: /* macro, it is a genuine */
1200: /* lvalue */
1201: Xxrepbuffer.mindex = XREPBUFSIZE - 1;
1202: Xxrepbuffer.windex = 0;
1203: Xxrepbuffer.rindex = 0;
1204: XXqueue.mindex = XREPBUFSIZE - 1;
1205: XXqueue.windex = 0;
1206: XXqueue.rindex = 0;
1207: WindowMapped = 0;
1208: baud_rate = 9600;
1209: min_padding_speed = 10000;
1210: must_write_spaces = 1;
1211: informflag = 1;
1212: MetaFlag = 1;
1213: visible_bell = 1;
1214: interrupt_input = 1;
1215: inverse_video = 1;
1216: bitblt = 0;
1217: PendingExposure = 0;
1218: IconWindow = 0;
1219:
1220: fix_screen_hook = xfixscreen;
1221: clear_screen_hook = XTclear_screen;
1222: clear_end_of_line_hook = XTclear_end_of_line;
1223: ins_del_lines_hook = XTins_del_lines;
1224: change_line_highlight_hook = XTchange_line_highlight;
1225: insert_chars_hook = XTinsert_chars;
1226: write_chars_hook = XTwrite_chars;
1227: delete_chars_hook = XTdelete_chars;
1228: ring_bell_hook = XTfeep;
1229: reset_terminal_modes_hook = XTreset_terminal_modes;
1230: set_terminal_modes_hook = XTset_terminal_modes;
1231: update_begin_hook = XTupdate_begin;
1232: update_end_hook = XTupdate_end;
1233: set_terminal_window_hook = XTset_terminal_window;
1234: read_socket_hook = XTread_socket;
1235: topos_hook = XTtopos;
1236: /* raw_topos_hook = XTraw_topos; */
1237: reassert_line_highlight_hook = XTreassert_line_highlight;
1238: scroll_region_ok = 1; /* we'll scroll partial screens */
1239: char_ins_del_ok = 0; /* just as fast to write the line */
1240: line_ins_del_ok = 1; /* we'll just blt 'em */
1241: fast_clear_end_of_line = 1; /* X does this well */
1242: memory_below_screen = 0; /* we don't remember what scrolls
1243: off the bottom */
1244: dont_calculate_costs = 1;
1245:
1246: fore = BlackPixel;
1247: back = WhitePixel;
1248: brdr = BlackPixel;
1249: mous = BlackPixel;
1250: curs = BlackPixel;
1251:
1252: fore_color = "black";
1253: back_color = "white";
1254: brdr_color = "black";
1255: mous_color = "black";
1256: curs_color = "black";
1257:
1258: XXpid = getpid ();
1259: XXcurrentfont = malloc (sizeof ("vtsingle") + 1);
1260: default_window = "=80x24+1+1";
1261: signal (SIGIO, XTread_socket);
1262: signal (SIGPIPE, XExitGracefully);
1263: if (XXcurrentfont == (char *) 0)
1264: {
1265: fprintf (stderr, "Memory allocation failure.\n");
1266: exit (-150);
1267: }
1268: strcpy (&XXcurrentfont[0], "vtsingle");
1269: XQueryWindow (RootWindow, &rootwindowinfo);
1270: strncpy (iconidentity, ICONTAG, MAXICID);
1271: XXborder = 1;
1272: screen_width = 80;
1273: screen_height = 66;
1274: XXxoffset = 0;
1275: XXyoffset = 0;
1276: XXdebug = 0;
1277: fontinfo = XOpenFont (&XXcurrentfont[0]);
1278: if (fontinfo == (FontInfo *) 0)
1279: {
1280: fprintf (stderr, "No font\n");
1281: exit (-98);
1282: }
1283: pixelwidth = screen_width * fontinfo->width + 1;
1284: pixelheight = screen_height * fontinfo->height + 1;
1285: XXwindow = XCreateWindow (RootWindow,
1286: XXxoffset /* Absolute horizontal offset */,
1287: XXyoffset /* Absolute Vertical offset */,
1288: pixelwidth, pixelheight,
1289: XXborder, BlackPixmap, WhitePixmap);
1290: if (!XXwindow)
1291: {
1292: fprintf (stderr, "Unable to create window.\n");
1293: exit (-97);
1294: }
1295:
1296: XXIconWindow = XCreateWindow (RootWindow, 0, 0, sink_width, sink_height,
1297: 2, WhitePixmap, (Pixmap) NULL);
1298:
1299: if (!XXIconWindow)
1300: {
1301: fprintf (stderr, "Unable to create icon window.\n");
1302: fflush (stderr);
1303: exit (-97);
1304: }
1305: XSelectInput (XXIconWindow, NoEvent);
1306: XXIconMask = XStoreBitmap(sink_mask_width, sink_mask_height, sink_mask_bits);
1307:
1308: XSelectInput (XXwindow, NoEvent);
1309: XSetResizeHint (XXwindow, fontinfo->width * 10, fontinfo->height *5,
1310: fontinfo->width, fontinfo->height);
1311:
1312: if (gethostname (&iconidentity[sizeof (ICONTAG) - 1],
1313: (MAXICID - 1) - sizeof (ICONTAG)))
1314: {
1315: iconidentity[sizeof (ICONTAG) - 2] = '\0';
1316: }
1317: XStoreName (XXwindow, &iconidentity[0]);
1318:
1319: EmacsCursor = XCreateCursor (16, 16, MouseCursor, MouseMask,
1320: 0, 0, BlackPixel, WhitePixel, GXcopy);
1321: XDefineCursor (XXwindow, EmacsCursor);
1322: /* Dirty kluge so maybe things will work right */
1323: XBitmapIcon();
1324: XTextIcon();
1325: flexlines = screen_height;
1326: if (!initialized)
1327: XPopUpWindow ();
1328: setxterm ();
1329: }
1330:
1331:
1332: /* Process all queued ExposeRegion events. */
1333: static
1334: dumpqueue ()
1335: {
1336: register int i;
1337: XExposeRegionEvent r;
1338: if ((XXqueue.rindex > XXqueue.mindex) ||
1339: (XXqueue.windex > XXqueue.mindex) ||
1340: (XXqueue.rindex < 0) ||
1341: (XXqueue.windex < 0))
1342: {
1343: PendingExposure = 1;
1344: }
1345: else
1346: while (XXqueue.rindex != XXqueue.windex)
1347: {
1348: if (CursorExists)
1349: CursorToggle ();
1350: unloadxrepbuffer (&r, &XXqueue);
1351: dumprectangle (r.y, r.x, r.height, r.width);
1352: }
1353: }
1354:
1355:
1356:
1357: XSetFlash ()
1358: {
1359: ring_bell_hook = XTflash;
1360: }
1361:
1362: XSetFeep ()
1363: {
1364: ring_bell_hook = XTfeep;
1365: }
1366:
1367:
1368: XNewFont (newname)
1369: register char *newname;
1370: {
1371: FontInfo *temp;
1372: int (*func) ();
1373: func = signal (SIGIO, SIG_IGN);
1374: XFlush ();
1375: if (XXdebug)
1376: fprintf (stderr, "Request id is %d\n", XXdisplay->request);
1377: temp = XOpenFont (newname);
1378: if (temp == (FontInfo *) 0)
1379: {
1380: (void) signal (SIGIO, func);
1381: if (QLength () > 0)
1382: {
1383: kill (XXpid, SIGIO);
1384: }
1385: return -1;
1386: }
1387: XCloseFont (fontinfo);
1388: fontinfo = temp;
1389: (void) signal (SIGIO, func);
1390: XSetResizeHint (XXwindow, fontinfo->width * 10, fontinfo->height *5,
1391: fontinfo->width, fontinfo->height);
1392: XSetWindowSize (screen_height, screen_width);
1393: if (QLength () > 0)
1394: {
1395: kill (XXpid, SIGIO);
1396: }
1397: return 0;
1398: }
1399:
1400: XFlipColor ()
1401: {
1402: Pixmap temp;
1403: int tempcolor;
1404: char *tempname;
1405: int (*func) ();
1406: Cursor temp_curs;
1407: CursorToggle ();
1408: func = signal (SIGIO, SIG_IGN);
1409: temp = XMakeTile(fore);
1410: XChangeBackground (XXwindow, temp);
1411: XFreePixmap (temp);
1412: temp = XMakeTile (back);
1413: if (XXborder)
1414: XChangeBorder (XXwindow, temp);
1415: XFreePixmap(temp);
1416: brdr = back;
1417: brdr_color = back_color;
1418: tempcolor = fore;
1419: fore = back;
1420: back = tempcolor;
1421: tempname = fore_color ;
1422: fore_color = back_color;
1423: back_color = tempname;
1424: /* XPixFill (XXwindow, 0, 0, screen_width * fontinfo->width,
1425: screen_height * fontinfo->height, back, ClipModeClipped,
1426: GXcopy, AllPlanes);
1427: dumprectangle(0, 0, screen_height * fontinfo->height,
1428: screen_width * fontinfo -> width);*/
1429: XRedrawDisplay();
1430: if (curs == WhitePixel)
1431: {
1432: curs = BlackPixel;
1433: curs_color = "black";
1434: }
1435: else if (curs == BlackPixel)
1436: {
1437: curs = WhitePixel;
1438: curs_color = "white";
1439: }
1440: if (mous == WhitePixel)
1441: {
1442: mous = BlackPixel;
1443: mous_color = "black";
1444: }
1445: else if (mous == BlackPixel)
1446: {
1447: mous = WhitePixel;
1448: mous_color = "white";
1449: }
1450: temp_curs = XCreateCursor(16, 16, MouseCursor, MouseMask, 0, 0,
1451: mous, back, GXcopy);
1452: XUndefineCursor (XXwindow);
1453: XDefineCursor (XXwindow, temp_curs);
1454: XFreeCursor (EmacsCursor);
1455: (void) signal (SIGIO, func);
1456: bcopy (&temp_curs, &EmacsCursor, sizeof (Cursor));
1457: CursorToggle ();
1458: XFlush ();
1459: }
1460:
1461: XSetOffset (xoff, yoff)
1462: register int xoff, yoff;
1463: {
1464: if (xoff < 0)
1465: {
1466: XXxoffset = rootwindowinfo.width + (++xoff) - pixelwidth - 4;
1467: }
1468: else
1469: {
1470: XXxoffset = xoff;
1471: }
1472: if (yoff < 0)
1473: {
1474: XXyoffset
1475: = rootwindowinfo.height + (++yoff) - pixelheight - 4;
1476: }
1477: else
1478: {
1479: XXyoffset = yoff;
1480: }
1481: XMoveWindow (XXwindow, XXxoffset, XXyoffset);
1482: /* XWarpMouse (XXwindow, pixelwidth >> 1, pixelheight >> 1); */
1483: }
1484:
1485: XSetWindowSize (rows, cols)
1486: register int rows, cols;
1487: {
1488: if (rows < 5) rows = 66;
1489: if (cols < 5) cols = 80;
1490: pixelwidth = cols * fontinfo->width + 1;
1491: pixelheight = rows * fontinfo->height + 1;
1492: XChangeWindow (XXwindow, pixelwidth, pixelheight);
1493: XFlush ();
1494: change_screen_size (rows, cols);
1495: PendingExposure = 0;
1496: }
1497:
1498: ()
1499: {
1500: if (WindowMapped)
1501: return;
1502: if(!x_edges_specified)
1503: Fx_rubber_band ();
1504: bitblt = 0;
1505: CursorExists = 0;
1506: VisibleX = 0;
1507: VisibleY = 0;
1508: WindowMapped = 1;
1509: XMapWindow (XXwindow);
1510: dumprectangle (0, 0, screen_height * fontinfo->height,
1511: screen_width * fontinfo->width);
1512: XSelectInput (XXwindow, KeyPressed | ExposeWindow |
1513: ButtonPressed | ExposeRegion | ExposeCopy);
1514: /* XWarpMouse(XXwindow, pixelwidth >> 1, pixelheight >> 1);*/
1515: XTtopos (0, 0);
1516: /* XRedrawDisplay();*/
1517: XFlush ();
1518: }
1519:
1520: spacecheck (mindex, rindex, windex, minfreespace)
1521: register int mindex, rindex, windex, minfreespace;
1522: {
1523: if ((rindex > mindex) || (windex > mindex))
1524: {
1525: fprintf (stderr, "Fatal Mouse Buffer Error.\n");
1526: fprintf (stderr, "%d = mindex, %d = rindex, %d = windex\n",
1527: mindex, rindex, windex);
1528: return -2;
1529: }
1530: if (windex >= rindex)
1531: {
1532: if ((mindex - (windex - rindex)) > minfreespace)
1533: return 0;
1534: }
1535: else
1536: {
1537: if (((rindex - windex) - 1) > minfreespace)
1538: return 0;
1539: }
1540: return -1;
1541: }
1542:
1543: loadxrepbuffer (p_xrep, p_buffer)
1544: register XEvent *p_xrep;
1545: register XREPBUFFER *p_buffer;
1546: {
1547: p_buffer->xrep[p_buffer->windex] = *p_xrep;
1548: if (p_buffer->windex == p_buffer->mindex)
1549: p_buffer->windex = 0;
1550: else
1551: p_buffer->windex++;
1552: }
1553:
1554: unloadxrepbuffer (p_xrep, p_buffer)
1555: register XEvent *p_xrep;
1556: register XREPBUFFER *p_buffer;
1557: {
1558: if (p_buffer->windex == p_buffer->rindex)
1559: return -1;
1560: *p_xrep = p_buffer->xrep[p_buffer->rindex];
1561: if (p_buffer->rindex == p_buffer->mindex)
1562: p_buffer->rindex = 0;
1563: else
1564: p_buffer->rindex++;
1565: return 0;
1566: }
1567:
1568: fixxrepbuffer ()
1569: {
1570: Xxrepbuffer.mindex = XREPBUFSIZE - 1;
1571: Xxrepbuffer.windex = 0;
1572: Xxrepbuffer.rindex = 0;
1573: }