1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998 John E. Davis
3  * This file is part of JED editor library source.
4  *
5  * You may distribute this file under the terms the GNU General Public
6  * License.  See the file COPYING for more information.
7  */
8 
9 #include "config.h"
10 #include "jed-feat.h"
11 
12 #define USE_NEW_META_CODE	1
13 #define HAS_IBM_NUMLOCK_CODE	0
14 #define SKIP_LOCALE_CODE	0
15 #ifndef HAVE_SETLOCALE
16 # define X_LOCALE		1
17 #endif
18 
19 /*{{{ Include Files */
20 
21 #ifndef VMS
22 # include <X11/Xlib.h>
23 # include <X11/Xutil.h>
24 /* #include <X11/Xos.h> */
25 # include <X11/Xatom.h>
26 # include <X11/keysym.h>
27 # include <X11/cursorfont.h>
28 # include <X11/Intrinsic.h>
29 /* # include <X11/Xmu/Atoms.h> */
30 # if !SKIP_LOCALE_CODE
31 #  if XtSpecificationRelease >= 6
32 #   define XJED_USE_R6IM
33 #   include <X11/Xlocale.h>
34 #  endif
35 # endif
36 #else
37 # include <decw$include/Xlib.h>
38 # include <decw$include/Xutil.h>
39 /* #include <decw$include/Xos.h> */
40 # include <decw$include/Xatom.h>
41 # include <decw$include/keysym.h>
42 # include <decw$include/cursorfont.h>
43 #endif
44 
45 #include <stdio.h>
46 #include <string.h>
47 #include <ctype.h>
48 
49 #include <slang.h>
50 
51 #include "jdmacros.h"
52 
53 /* #include "xterm.h"*/
54 #include "buffer.h"
55 #include "display.h"
56 #include "sysdep.h"
57 #include "screen.h"
58 #include "keymap.h"
59 #include "hooks.h"
60 #include "ins.h"
61 #include "ledit.h"
62 #include "misc.h"
63 #include "cmds.h"
64 #include "sig.h"
65 #include "file.h"
66 #include "vterm.h"
67 #include "kanji.h"
68 
69 /*}}}*/
70 
71 /*{{{ Static Global Variables */
72 
73 static int JX_Screen_Cols;
74 static int JX_Screen_Rows;
75 static int JX_Term_Cannot_Scroll = 0;
76 static int JX_Term_Cannot_Insert = 0;
77 static int JX_Use_Ansi_Colors = 1;
78 static int JX_Ignore_Beep = 3;
79 static int JX_Blink_Mode = 1;
80 static int JX_MultiClick_Time = 500;   /* milliseconds */
81 
82 #ifdef XJED_USE_R6IM
83 static char *R6IM_Input_Method = NULL;
84 static XIMStyle R6IM_Input_Style = 0;
85 static char *R6IM_Preedit_Type = "Root";
86 static XIC R6IM_Xic;
87 static void i18init(void);
88 static XPoint R6IM_Spot;
89 static XVaNestedList R6IM_Preedit_Attr;
90 static void move_input_position (void);
91 static void set_geometry (XEvent *, XIMStyle, char *);
92 #endif
93 
94 static char *The_Xserver_Vendor;
95 
96 static int Rev_Vid_Flag;
97 static int X_Alt_Char = 27;
98 static KeySym X_Last_Keysym;
99 static int X_Warp_Pending = 0;
100 
101 typedef struct /*{{{*/
102 {
103    GC gc[3];
104    unsigned long fg, bg;
105    char *fg_name;
106    char *bg_name;
107    int dirty;
108 }
109 /*}}}*/
110 GC_Info_Type;
111 
112 typedef struct /*{{{*/
113 {
114    Window w;
115    Atom wm_del_win;		       /* delete window protocol */
116 
117    int height, width;
118    int border;			       /* inside border */
119    int o_border;		       /* outside border */
120    Colormap color_map;
121 
122    /* font information */
123    XFontStruct *font, *kanji_font, *roman_font;
124    char *font_name, *kanji_font_name, *roman_font_name;
125    int font_height, font_width, font_base;
126    int kanji_font_height, kanji_font_width, kanji_font_base;
127    int roman_font_height, roman_font_width, roman_font_base;
128 
129    /* GC info */
130    GC_Info_Type *text_gc;
131    GC current_gc[3];
132    GC_Info_Type pointer_gc;
133 
134    int vis_curs_row, vis_curs_col;     /* position of VISIBLE cursor */
135 
136    /* flags */
137    int cursor_showing;		       /* true if widow has cursor showing */
138    int focus;			       /* true if window has focus */
139    int window_mapped;		       /* true if window is mapped */
140 
141    /* Window tty parameters */
142    int insert_mode;		       /* true if inserting */
143    int scroll_r1,  scroll_r2;	       /* scrolling region */
144    int cursor_row, cursor_col;	       /* row column of cursor (0, 0) origin */
145 
146    int visible;			       /* from visibilitynotify */
147    Cursor mouse;
148 
149 }
150 /*}}}*/
151 JXWindow_Type;
152 
153 static JXWindow_Type This_X_Window;
154 static JXWindow_Type *XWin;
155 
156 static Display *This_XDisplay;
157 static Window This_XWindow;
158 static int This_XScreen;
159 static int Performing_Update;
160 static int Check_Buffers_Pending;
161 static int No_XEvents;		       /* if true, do nothing */
162 
163 typedef struct /*{{{*/
164 {
165    char *name;
166    char *name1;
167    int type;
168    char *value;
169    char **dflt;
170 }
171 
172 /*}}}*/
173 XWindow_Arg_Type;
174 
175 #define XJED_CLASS	"XTerm"
176 #define XJED_RESOURCE	"xjed"
177 
178 static char *This_App_Name = XJED_RESOURCE;
179 static char *This_App_Title = "XJed";
180 /* #define Default_Geometry "80x24+0-0" */
181 #define Default_Geometry "80x24"
182 static char *This_Geometry = NULL;
183 static char *This_Font_Name = "a14";
184 static char *This_Kanji_Font_Name = "k14";
185 static char *This_Roman_Font_Name = "r14";
186 static char *This_Border_Width_Name = "0";
187 static char *This_MFG = "green";
188 static char *This_MBG = "white";
189 static char *Iconic = NULL;
190 
191 static Atom Compound_Text_Atom, Xjed_Prop;
192 static XEvent Current_Event;
193 static char *Selection_Send_Data = NULL;
194 static int receive_selection (XEvent *);
195 static int send_selection (XEvent *);
196 
197 static GC_Info_Type Default_GC_Info[JMAX_COLORS] = /*{{{*/
198 {
199    {{NULL, NULL, NULL}, 0, 0, "black", "white"},     /* NORMAL */
200    {{NULL, NULL, NULL}, 0, 0, "green", "red"},       /* CURSOR */
201    {{NULL, NULL, NULL}, 0, 0, "default", "cyan"},   /* STATUS */
202    {{NULL, NULL, NULL}, 0, 0, "default", "magenta"},      /* REGION */
203    {{NULL, NULL, NULL}, 0, 0, "default", "cyan"},      /* MENU */
204    {{NULL, NULL, NULL}, 0, 0, "default", "default"},     /* operator */
205    {{NULL, NULL, NULL}, 0, 0, "green", "default"},     /* numbers */
206    {{NULL, NULL, NULL}, 0, 0, "blue", "default"},      /* strings */
207    {{NULL, NULL, NULL}, 0, 0, "default", "gray"},      /* comments */
208    {{NULL, NULL, NULL}, 0, 0, "default", "default"},      /* delimeters */
209    {{NULL, NULL, NULL}, 0, 0, "magenta", "default"},      /* preprocess */
210    {{NULL, NULL, NULL}, 0, 0, "blue", "default"},      /* message */
211    {{NULL, NULL, NULL}, 0, 0, "red", "default"},      /* error */
212    {{NULL, NULL, NULL}, 0, 0, "magenta", "default"},      /* dollar */
213    {{NULL, NULL, NULL}, 0, 0, "red", "default"},       /* keyword */
214    {{NULL, NULL, NULL}, 0, 0, "green", "default"},       /* keyword1 */
215    {{NULL, NULL, NULL}, 0, 0, "red", "default"},       /* keyword2 */
216    {{NULL, NULL, NULL}, 0, 0, "green", "default"}       /* ... fold mark */
217 };
218 
219 /*}}}*/
220 
221 /* cheat a little, use VOID_TYPE for boolean arguments */
222 static XWindow_Arg_Type X_Arg_List[] = /*{{{*/
223 {
224    /* These MUST be in this order!!! */
225 #define XARG_DISPLAY	0
226      {"Display",		"d", 	STRING_TYPE,	NULL,	NULL},
227 #define XARG_NAME	1
228      {"Name",		NULL,	STRING_TYPE,	NULL,	&This_App_Name},
229 #define XARG_GEOMETRY	2
230      {"Geometry",		NULL, 	STRING_TYPE,	NULL,	&This_Geometry},
231 
232 #define XARG_START	2
233 #if 1
234      /* Note: it's good to look for
235       * `font', `background', `foreground'
236       * instead of
237       * `Font', `background', `foreground'
238       * so that XTerm names can be used
239       * (resource vs. class names)
240       *
241       * also, change order of names a little?
242       */
243      {"font",		"fn",	STRING_TYPE,	NULL,	&This_Font_Name},
244      {"KanjiFont",	"kfn",	STRING_TYPE,	NULL,	&This_Kanji_Font_Name},
245      {"RomanFont",	"rfn",	STRING_TYPE,	NULL,	&This_Roman_Font_Name},
246 #ifdef XJED_USE_R6IM
247      {"inputMethod",      "im",   STRING_TYPE,    NULL,   &R6IM_Input_Method},
248      {"inputStyle",       "is",   STRING_TYPE,    NULL,   &R6IM_Preedit_Type},
249 #endif
250      {"fgMouse",		"mfg", 	STRING_TYPE,	NULL,	&This_MFG},
251      {"bgMouse",		"mbg", 	STRING_TYPE,	NULL,	&This_MBG},
252      {"background",	"bg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JNORMAL_COLOR].bg_name},
253      {"foreground",	"fg",	STRING_TYPE,	NULL,	&Default_GC_Info[JNORMAL_COLOR].fg_name},
254      {"fgStatus",	"sfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JSTATUS_COLOR].fg_name},
255      {"bgStatus",	"sbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JSTATUS_COLOR].bg_name},
256      {"fgRegion",	"rfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JREGION_COLOR].fg_name},
257      {"bgRegion",	"rbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JREGION_COLOR].bg_name},
258      {"fgCursor",	"cfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JCURSOR_COLOR].fg_name},
259      {"bgCursor",	"cbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JCURSOR_COLOR].bg_name},
260      {"fgMenu",		"fgm", 	STRING_TYPE,	NULL,	&Default_GC_Info[JMENU_COLOR].fg_name},
261      {"bgMenu",		"bgm", 	STRING_TYPE,	NULL,	&Default_GC_Info[JMENU_COLOR].bg_name},
262      {"fgOperator",	"fgop",	STRING_TYPE,	NULL,	&Default_GC_Info[JOP_COLOR].fg_name},
263      {"bgOperator",	"bgop",	STRING_TYPE,	NULL,	&Default_GC_Info[JOP_COLOR].bg_name},
264      {"fgNumber",		"fgnm",	STRING_TYPE,	NULL,	&Default_GC_Info[JNUM_COLOR].fg_name},
265      {"bgNumber",		"bgnm",	STRING_TYPE,	NULL,	&Default_GC_Info[JNUM_COLOR].bg_name},
266      {"fgString",		"fgst",	STRING_TYPE,	NULL,	&Default_GC_Info[JSTR_COLOR].fg_name},
267      {"bgString",		"bgst",	STRING_TYPE,	NULL,	&Default_GC_Info[JSTR_COLOR].bg_name},
268      {"fgComments",	"fgco",	STRING_TYPE,	NULL,	&Default_GC_Info[JCOM_COLOR].fg_name},
269      {"bgComments",	"bgco",	STRING_TYPE,	NULL,	&Default_GC_Info[JCOM_COLOR].bg_name},
270      {"fgKeyword",	"fgkw",	STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR].fg_name},
271      {"bgKeyword",	"bgkw",	STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR].bg_name},
272      {"fgKeyword1",	"fgkw1",STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR + 1].fg_name},
273      {"bgKeyword1",	"bgkw1",STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR + 1].bg_name},
274      {"fgDelimiter",	"fgde",	STRING_TYPE,	NULL,	&Default_GC_Info[JDELIM_COLOR].fg_name},
275      {"bgDelimiter",	"bgde",	STRING_TYPE,	NULL,	&Default_GC_Info[JDELIM_COLOR].bg_name},
276      {"fgPreprocess",	"fgpr",	STRING_TYPE,	NULL,	&Default_GC_Info[JPREPROC_COLOR].fg_name},
277      {"bgPreprocess",	"bgpr",	STRING_TYPE,	NULL,	&Default_GC_Info[JPREPROC_COLOR].bg_name},
278      {"bgMessage",	"bgms",	STRING_TYPE,	NULL,	&Default_GC_Info[JMESSAGE_COLOR].bg_name},
279      {"fgMessage",	"fgms",	STRING_TYPE,	NULL,	&Default_GC_Info[JMESSAGE_COLOR].fg_name},
280      {"bgError",		"bger",	STRING_TYPE,	NULL,	&Default_GC_Info[JERROR_COLOR].bg_name},
281      {"fgError",		"fger",	STRING_TYPE,	NULL,	&Default_GC_Info[JERROR_COLOR].fg_name},
282      {"fgDots",		"fgdt",	STRING_TYPE,	NULL,	&Default_GC_Info[JDOTS_COLOR].bg_name},
283      {"bgDots",		"bgdt",	STRING_TYPE,	NULL,	&Default_GC_Info[JDOTS_COLOR].bg_name},
284 
285      {"BorderWidth",	"bw", 	STRING_TYPE,	NULL,	&This_Border_Width_Name},
286      {"title",		NULL,	STRING_TYPE,	NULL,	&This_App_Title},
287      {"BorderColor",	"bd", 	STRING_TYPE,	NULL,	NULL},
288      {"Iconic",		"ic",	VOID_TYPE,	NULL,	&Iconic},
289      {"xrm",		NULL,	STRING_TYPE,	NULL,	NULL},
290      {NULL,		NULL,	0,		NULL,	NULL}
291 #else
292      {"Font",		"fn",	STRING_TYPE,	NULL,	&This_Font_Name},
293 #ifdef XJED_USE_R6IM
294      {"inputMethod",      "im",   STRING_TYPE,    NULL,   &R6IM_Input_Method},
295      {"inputStyle",       "is",   STRING_TYPE,    NULL,   &R6IM_Preedit_Type},
296 #endif
297      {"Mouse_fg",		"mfg", 	STRING_TYPE,	NULL,	&This_MFG},
298      {"Mouse_bg",		"mbg", 	STRING_TYPE,	NULL,	&This_MBG},
299      {"background",	"bg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JNORMAL_COLOR].bg_name},
300      {"foreground",	"fg",	STRING_TYPE,	NULL,	&Default_GC_Info[JNORMAL_COLOR].fg_name},
301      {"Status_fg",	"sfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JSTATUS_COLOR].fg_name},
302      {"Status_bg",	"sbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JSTATUS_COLOR].bg_name},
303      {"Region_fg",	"rfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JREGION_COLOR].fg_name},
304      {"Region_bg",	"rbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JREGION_COLOR].bg_name},
305      {"Cursor_fg",	"cfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JCURSOR_COLOR].fg_name},
306      {"Cursor_bg",	"cbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JCURSOR_COLOR].bg_name},
307      {"Menu_fg",		"mfg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JMENU_COLOR].fg_name},
308      {"Menu_bg",		"mbg", 	STRING_TYPE,	NULL,	&Default_GC_Info[JMENU_COLOR].bg_name},
309      {"Operator_fg",	"opfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JOP_COLOR].fg_name},
310      {"Operator_bg",	"opbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JOP_COLOR].bg_name},
311      {"Number_fg",	"nmfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JNUM_COLOR].fg_name},
312      {"Number_bg",	"nmbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JNUM_COLOR].bg_name},
313      {"String_fg",	"stfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JSTR_COLOR].fg_name},
314      {"String_bg",	"stbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JSTR_COLOR].bg_name},
315      {"Comments_fg",	"cofg",	STRING_TYPE,	NULL,	&Default_GC_Info[JCOM_COLOR].fg_name},
316      {"Comments_bg",	"cobg",	STRING_TYPE,	NULL,	&Default_GC_Info[JCOM_COLOR].bg_name},
317      {"Keyword_fg",	"kwfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR].fg_name},
318      {"Keyword_bg",	"kwbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR].bg_name},
319      {"Keyword1_fg",	"kw1fg",STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR + 1].fg_name},
320      {"Keyword1_bg",	"kw1bg",STRING_TYPE,	NULL,	&Default_GC_Info[JKEY_COLOR + 1].bg_name},
321      {"Delimiter_fg",	"defg",	STRING_TYPE,	NULL,	&Default_GC_Info[JDELIM_COLOR].fg_name},
322      {"Delimiter_bg",	"debg",	STRING_TYPE,	NULL,	&Default_GC_Info[JDELIM_COLOR].bg_name},
323      {"Preprocess_fg",	"prfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JPREPROC_COLOR].fg_name},
324      {"Preprocess_bg",	"prbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JPREPROC_COLOR].bg_name},
325      {"Message_bg",	"msbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JMESSAGE_COLOR].bg_name},
326      {"Message_fg",	"msfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JMESSAGE_COLOR].fg_name},
327      {"Error_fg",		"erfg",	STRING_TYPE,	NULL,	&Default_GC_Info[JERROR_COLOR].fg_name},
328      {"Error_bg",		"erbg",	STRING_TYPE,	NULL,	&Default_GC_Info[JERROR_COLOR].bg_name},
329 
330      {"Borderwidth",	"bw", 	STRING_TYPE,	NULL,	&This_Border_Width_Name},
331      {"Title",		NULL,	STRING_TYPE,	NULL,	&This_App_Title},
332      {"Bordercolor",	"bd", 	STRING_TYPE,	NULL,	NULL},
333      {"Iconic",		"ic",	VOID_TYPE,	NULL,	&Iconic},
334      {"xrm",		NULL,	STRING_TYPE,	NULL,	NULL},
335      {NULL,		NULL,	0,		NULL,	NULL}
336 #endif
337 };
338 
339 /*}}}*/
340 
341 /*}}}*/
342 
hide_cursor(void)343 static void hide_cursor (void) /*{{{*/
344 {
345    unsigned short *s;
346    XChar2b ch2;
347    GC gc;
348    char ch, *ss;
349    unsigned char k[2];
350    int color;
351    int b = XWin->border, col = XWin->vis_curs_col, row = XWin->vis_curs_row;
352    int c = XWin->vis_curs_col;
353 
354    if (No_XEvents
355        || (VTerm_Display == NULL)
356        || (XWin->cursor_showing == 0))
357      return;
358 
359    XWin->cursor_showing = 0;
360 
361    s = VTerm_Display[row] + col;
362 #if KANJI_NEW_STUFF_BETA
363    if(SKanaToDKana)
364      {
365 	int i;
366 	unsigned short *ss;
367 	unsigned char cc;
368 
369 	for(ss = VTerm_Display[row];ss<s;ss++)
370 	  {
371 	     cc = *ss & 0xFF;
372 	     if(iskanji(cc)) {
373 		ss++;
374 	     }
375 	     else if(ishkana(cc))
376 	       {
377 		  if(cc == 0xde || cc == 0xdf)
378 		    s++;
379 		  else
380 		    s--;
381 	       }
382 	  }
383 	cc = *s & 0xFF;
384 	if(cc == 0xde || cc == 0xdf)
385 	  {
386 	     if (s == ss)
387 	       s++;
388 	  }
389  	else if((cc = *ss & 0xFF) == 0xde || cc == 0xdf)
390 	  {
391 	     if (s != ss)
392 	       c--;
393 	  }
394      }
395 #endif
396    ch = *s & 0xFF;
397    color = (*s >> 8);
398 
399 #if KANJI_NEW_STUFF_BETA
400    col = c;
401 #endif
402    if(iskanji(ch))
403      {
404 	k[0] = ch;
405 	k[1] = (unsigned char) (*(s+1) & 0xFF);
406 	kSLcodeconv[kSLcode][kSLdisplay_code] (k, k);
407 
408 	ch2.byte1 = k[0] & 0x7f;
409 	ch2.byte2 = k[1] & 0x7f;
410 	gc = XWin->text_gc[*s >> 8].gc[1];
411      }
412    else if (ishkana(ch))
413      {
414 #if KANJI_NEW_STUFF_BETA
415 	if(SKanaToDKana)
416 	  {
417 	     unsigned char *p;
418 	     int i = 1, j;
419 	     k[0] = ch;
420 	     if(ishkana(*(s+1) & 0xFF))
421 	       {
422 		  k[1] = (unsigned char) (*(s+1) & 0xFF);
423 		  i++;
424 	       }
425 	     j = i;
426 
427 	     p = KanjiCodeConv (k, &i, kSLcode, EUC, SKanaToDKana);
428 	     ch2.byte1 = p[0] & 0x7f;
429 	     ch2.byte2 = p[1] & 0x7f;
430 	     gc = XWin->text_gc[*s >> 8].gc[1];
431 	     if (p != k) SLfree(p);
432 	  }
433 	else
434 #endif /* KANJI_NEW_STUFF_BETA */
435 	  {
436 	     ch2.byte1 = 0;
437 	     ch2.byte2 = ch;
438 	     gc = XWin->text_gc[*s >> 8].gc[2];
439 	  }
440      }
441    else
442      {
443 	ch2.byte1 = 0;
444 	ch2.byte2 = ch;
445 	gc = XWin->text_gc[*s >> 8].gc[0];
446      }
447 
448 #if 1	/* KANJI */
449    XDrawImageString16 (This_XDisplay, XWin->w,
450 		       gc,
451 		       col * XWin->font_width + b,
452 		       row * XWin->font_height + b + XWin->font_base,
453 		       &ch2, 1);
454 #else
455    XDrawImageString (This_XDisplay, XWin->w,
456 		     XWin->text_gc[color].gc,
457 		     col * XWin->font_width + b,
458 		     row * XWin->font_height + b + XWin->font_base,
459 		     &ch, 1);
460 #endif
461 
462 }
463 
464 /*}}}*/
465 
466 /* This routine assumes that cursor is in the correct location.  The
467    cursor is placed at the end of the string.  Even if we are unable to
468  * write the string, make sure that the cursor is moved as if we did
469  * the write. The main reason for this is that our X cursor must track
470  * the vterm cursor so that the display gets updated properly.
471  * Otherwise, smart_puts will call forward_cursor and then write to the
472  * virtual display, and get that wrong because forward_cursor assumes
473  * that the XWin cursor is correct.
474  */
tt_write(char * s,int n)475 static void tt_write(char *s, int n) /*{{{*/
476 {
477    vterm_write_nchars (s, (unsigned int) n);
478 
479    if ((No_XEvents == 0)
480        && (XWin->window_mapped))
481      {
482 	int b = XWin->border;
483 	XChar2b *s2;
484 	int i, j, nchars = 0, c = 0;
485 	unsigned char k[2];
486 	int len = n;
487 
488 
489 	if (XWin->cursor_showing) hide_cursor ();
490 
491 #if 1	/* KANJI */
492     s2 = (XChar2b *)malloc(sizeof(XChar2b) * len);
493     for(i = 0, nchars = 0; i < len; ++i) {
494       if(iskanji(s[i])) {       /* KANJI ? */
495 	 k[0] = s[i]; k[1] = s[i+1];
496 	 kSLcodeconv[kSLcode][kSLdisplay_code] (k, k);
497 /*	 sjistojis(k, k); */
498           s2[nchars].byte1 = k[0];
499           s2[nchars].byte2 = k[1];
500 	 i++;
501       }
502       else if(ishkana(s[i])) {
503 #if KANJI_NEW_STUFF_BETA
504 	 if(SKanaToDKana)
505 	   {
506 	      unsigned char *p;
507 	      int ii = 1, jj;
508 	      k[0] = s[i];
509 	      if(ishkana(s[i+1]))
510 		{
511 		   k[1] = (unsigned char) (s[i+1]);
512 		   ii++;
513 		}
514 	      jj = ii;
515 
516 	      p = KanjiCodeConv(k, &ii, kSLcode, EUC, SKanaToDKana);
517 	      s2[nchars].byte1 = p[0] & 0x7f;
518 	      s2[nchars].byte2 = p[1] & 0x7f;
519 	      if(p != k) SLfree(p);
520 	      if(ii == 2 && jj == 2) i++;
521 	   }
522 	 else
523 #endif /* KANJI_NEW_STUFF_BETA */
524 	   {
525 	      s2[nchars].byte1 = 0;
526 	      s2[nchars].byte2 = s[i];
527 	   }
528       }
529       else {
530           s2[nchars].byte1 = 0;
531           s2[nchars].byte2 = s[i];
532       }
533       ++nchars;
534     }
535     i = 0;
536     c = 0;
537     while(i < nchars) {
538       if(s2[i].byte1 != 0) {  /* KANJI */
539           j = i;
540           while(i < nchars && s2[i].byte1 != 0) {
541               ++i;
542           }
543           XDrawImageString16(This_XDisplay, This_XWindow, XWin->current_gc[1],
544               (XWin->cursor_col + c) * XWin->font_width + b,
545               (XWin->cursor_row) * XWin->font_height + b + XWin->font_base,
546               &s2[j], (i - j));
547           c += ((i - j) * 2);
548       } else if(ishkana(s2[i].byte2)) {
549           j = i;
550           while(i < nchars && s2[i].byte1 == 0 && ishkana(s2[i].byte2)) {
551               ++i;
552           }
553           XDrawImageString16(This_XDisplay, This_XWindow, XWin->current_gc[2],
554               (XWin->cursor_col + c) * XWin->font_width + b,
555               (XWin->cursor_row) * XWin->font_height + b + XWin->font_base,
556               &s2[j], (i - j));
557           c += (i - j);
558       } else {
559           j = i;
560           while(i < nchars && s2[i].byte1 == 0 && !ishkana(s2[i].byte2)) {
561               ++i;
562           }
563           XDrawImageString16(This_XDisplay, This_XWindow, XWin->current_gc[0],
564               (XWin->cursor_col + c) * XWin->font_width + b,
565               (XWin->cursor_row) * XWin->font_height + b + XWin->font_base,
566               &s2[j], (i - j));
567           c += (i - j);
568       }
569     }
570     SLfree((char*)s2);
571 #else
572 	XDrawImageString(This_XDisplay, This_XWindow, XWin->current_gc,
573 			 (XWin->cursor_col) * XWin->font_width + b,
574 			 (XWin->cursor_row) * XWin->font_height + b + XWin->font_base,
575 			 s, n);
576 #endif	/* KANJI */
577      }
578 
579    XWin->cursor_col += n;
580    if (XWin->cursor_col >= JX_Screen_Cols) XWin->cursor_col = JX_Screen_Cols - 1;
581 }
582 
583 /*}}}*/
584 
copy_rect(int x1,int y1,int x2,int y2,int x3,int y3)585 static void copy_rect(int x1, int y1, int x2, int y2, int x3, int y3) /*{{{*/
586 {
587    int w, h;
588 
589    if (No_XEvents || (XWin->window_mapped == 0))
590      return;
591 
592    w = (x2 - x1) * XWin->font_width;
593    h = (y2 - y1) * XWin->font_height;
594 
595    if ((w <= 0) || (h <= 0)) return;
596 
597    x3 = XWin->border + x3 * XWin->font_width;
598    x1 = XWin->border + x1 * XWin->font_width;
599    y3 = XWin->border + y3 * XWin->font_height;
600    y1 = XWin->border + y1 * XWin->font_height;
601    hide_cursor ();
602    XCopyArea (This_XDisplay, This_XWindow, This_XWindow, XWin->current_gc[0],
603 	      x1, y1, w, h, x3, y3);
604 }
605 
606 /*}}}*/
607 
blank_rect(int x1,int y1,int x2,int y2)608 static void blank_rect (int x1,  int y1, int x2, int y2) /*{{{*/
609 {
610    int w, h;
611 
612    if (No_XEvents || (XWin->window_mapped == 0)) return;
613 
614    w = (x2 - x1) * XWin->font_width;
615    h = (y2 - y1) * XWin->font_height;
616 
617    if ((w <= 0) || (h <= 0)) return;
618 
619    x1 = XWin->border + x1 * XWin->font_width;
620    y1 = XWin->border + y1 * XWin->font_height;
621    hide_cursor ();
622    XClearArea (This_XDisplay, This_XWindow, x1, y1, w, h, 0);
623 }
624 
625 /*}}}*/
626 
JX_set_scroll_region(int r1,int r2)627 static void JX_set_scroll_region(int r1, int r2) /*{{{*/
628 {
629    XWin->scroll_r1 = r1;
630    XWin->scroll_r2 = r2;
631    vterm_set_scroll_region (r1, r2);
632 }
633 
634 /*}}}*/
635 
JX_reset_scroll_region(void)636 static void JX_reset_scroll_region (void) /*{{{*/
637 {
638    JX_set_scroll_region (0, JX_Screen_Rows - 1);
639 }
640 
641 /*}}}*/
642 
show_cursor(void)643 static void show_cursor (void) /*{{{*/
644 {
645    unsigned short *s;
646    char ch, *ss;
647    int c, r, b;
648    GC_Info_Type *gc_info;
649    GC gc;
650    XGCValues gcv;
651    unsigned long gcv_mask;
652 
653    if (No_XEvents
654        || (VTerm_Display == NULL))
655      return;
656 
657    if (XWin->cursor_showing) hide_cursor ();
658 
659    XWin->cursor_showing = 1;
660    r = XWin->vis_curs_row = XWin->cursor_row;
661    c = XWin->vis_curs_col = XWin->cursor_col;
662    b = XWin->border;
663 
664    s = VTerm_Display[r] + c;
665 /*   c = calculate_column ()-1; */
666 #if KANJI_NEW_STUFF_BETA
667    if(SKanaToDKana)
668      {
669 	int i;
670 	unsigned short *ss;
671 	unsigned char cc;
672 
673 	for(ss = VTerm_Display[r];ss<s;ss++)
674 	  {
675 	     cc = *ss & 0xFF;
676 	     if(iskanji(cc)) {
677 		ss++;
678 	     }
679 	     else if(ishkana(cc)) {
680 		if(cc == 0xde || cc == 0xdf)
681 		  { s++; }
682 		else
683 		  s--;
684 	     }
685 	  }
686 	cc = *s & 0xFF;
687 	if(cc == 0xde || cc == 0xdf) {
688 	   if( s == ss ) {
689 	      s++;
690 	   }
691 	}
692 	else if((cc = *ss & 0xFF) == 0xde || cc == 0xdf) {
693 	   if( s != ss ) {
694 	      c--;
695 	   }
696 	}
697      }
698 #endif
699    ch = *s & 0xFF;
700 
701    gc_info = &(XWin->text_gc[JCURSOR_COLOR]);
702 #if 0 /* KANJI */
703    gc = gc_info->gc;
704 #endif
705 
706    if (XWin->focus)
707      {
708 	XChar2b ch2;
709 	unsigned char k[2];
710 
711 #if 0	/* KANJI */
712 	if (gc_info->dirty)
713 	  {
714 	     gc_info->dirty = 0;
715 	     gcv.foreground = gc_info->fg;
716 	     gcv.background = gc_info->bg;
717 	     gcv_mask = GCForeground | GCBackground;
718 	     XChangeGC(This_XDisplay, gc, gcv_mask, &gcv);
719 	  }
720 	XDrawImageString(This_XDisplay, This_XWindow,
721 			 gc,
722 			 c * XWin->font_width + b,
723 			 r * XWin->font_height + b + XWin->font_base,
724 			 &ch, 1);
725 #else
726 	if(iskanji(ch))
727 	  {
728 	     k[0] = ch; k[1] = *(s+1) & 0xff;
729 	     kSLcodeconv[kSLcode][kSLdisplay_code] (k, k);
730 	     ch2.byte1 = k[0] & 0x7f;
731 	     ch2.byte2 = k[1] & 0x7f;
732 	     gc = gc_info->gc[1];
733 	  }
734 	else if(ishkana(ch))
735 	  {
736 #if KANJI_NEW_STUFF_BETA
737 	     if(SKanaToDKana)
738 	       {
739 		  unsigned char *p;
740 		  int ii = 1, jj;
741 		  k[0] = ch;
742 #if KANJI_NEW_STUFF_BETA /* NEW NEW BETA */
743 		  if(ishkana(*(s+1) & 0xff))
744 		    {
745 		       k[1] = (unsigned char) *(s+1);
746 		       ii++;
747 		    }
748 #else
749 		  if(ishkana(*(s+1) & 0xff))
750 		    {
751 		       k[1] = (unsigned char) (*(s+1) & 0xff);
752 		       ii++;
753 		    }
754 #endif
755 
756 		  p = KanjiCodeConv(k, &ii, kSLcode, EUC, SKanaToDKana);
757 		  ch2.byte1 = p[0] & 0x7f;
758 		  ch2.byte2 = p[1] & 0x7f;
759 		  gc = gc_info->gc[1];
760 		  if(p != k) SLfree(p);
761 	       }
762 	     else
763 #endif /* KANJI_NEW_STUFF_BETA */
764 	       {
765 		  ch2.byte1 = 0;
766 		  ch2.byte2 = ch;
767 		  gc = XWin->text_gc[JCURSOR_COLOR].gc[2];
768 	       }
769 	  }
770 	else
771 	  {
772 /*	     ch2.byte2 = JScreen[r].old[c]; */
773 	     ch2.byte2 = ch;
774 	     ch2.byte1 = 0;
775 	     gc = XWin->text_gc[JCURSOR_COLOR].gc[0];
776 	  }
777 
778 	if (gc_info->dirty)
779 	  {
780 	     gc_info->dirty = 0;
781 	     gcv.foreground = gc_info->fg;
782 	     gcv.background = gc_info->bg;
783 	     gcv_mask = GCForeground | GCBackground;
784 	     XChangeGC(This_XDisplay, gc, gcv_mask, &gcv);
785 	  }
786 	XDrawImageString16(This_XDisplay, This_XWindow,
787 			   gc,
788 			   c * XWin->font_width + b,
789 			   r * XWin->font_height + b + XWin->font_base,
790 			   &ch2, 1);
791 #endif
792      }
793    else
794      {
795         unsigned int fw, fh;
796 
797 	gc_info->dirty = 1;
798 	gcv.foreground = gc_info->bg;
799 	gcv.background = gc_info->fg;
800 	gcv_mask = GCForeground | GCBackground;
801 
802         if(iskanji(ch))
803 	  {
804 	     gc = XWin->text_gc[JCURSOR_COLOR].gc[1];
805 	     fw = XWin->kanji_font_width;
806 	     fh = XWin->kanji_font_height;
807 	  }
808 	else if(ishkana(ch))
809 	  {
810 #if KANJI_NEW_STUFF_BETA
811 	     if(SKanaToDKana)
812 	       {
813 		  gc = XWin->text_gc[JCURSOR_COLOR].gc[1];
814 		  fw = XWin->kanji_font_width;
815 		  fh = XWin->kanji_font_height;
816 	       }
817 	     else
818 #endif /* KANJI_NEW_STUFF_BETA */
819 	       {
820 		  gc = XWin->text_gc[JCURSOR_COLOR].gc[2];
821 		  fw = XWin->roman_font_width;
822 		  fh = XWin->roman_font_height;
823 	       }
824 	  }
825 	else
826 	  {
827 	     gc = XWin->text_gc[JCURSOR_COLOR].gc[0];
828 	     fw = XWin->font_width;
829 	     fh = XWin->font_height;
830 	  }
831 	XChangeGC(This_XDisplay, gc, gcv_mask, &gcv);
832 
833 #if 0   /* KANJI */
834 	XDrawRectangle( This_XDisplay, This_XWindow,
835 		       gc,
836 		       c * XWin->font_width + b,
837 		       r * XWin->font_height + b,
838 		       XWin->font_width - 1,
839 		       XWin->font_height - 1);
840 #else
841 	XDrawRectangle( This_XDisplay, This_XWindow, gc,
842 		       c * XWin->font_width + b, r * XWin->font_height + b,
843 		       fw - 1, fh - 1);
844 #endif
845      }
846 
847    XFlush(This_XDisplay);
848 }
849 
850 /*}}}*/
851 
toggle_cursor(int on)852 static void toggle_cursor (int on) /*{{{*/
853 {
854    if (on)
855      {
856 	if (XWin->focus) return;
857 	XWin->focus = 1;
858      }
859    else
860      {
861 	if (XWin->focus == 0) return;
862 	XWin->focus = 0;
863      }
864    show_cursor ();
865 }
866 
867 /*}}}*/
868 
JX_write_string(char * s)869 static void JX_write_string (char *s) /*{{{*/
870 {
871    tt_write(s, strlen(s));
872    if (Performing_Update) return;
873    show_cursor ();
874 }
875 
876 /*}}}*/
877 
JX_goto_rc(int r,int c)878 static void JX_goto_rc(int r, int c) /*{{{*/
879 {
880    if (XWin == NULL) return;
881    if (XWin->cursor_showing) hide_cursor ();
882    if (r >= JX_Screen_Rows) r = JX_Screen_Rows - 1;
883    if (c >= JX_Screen_Cols) c = JX_Screen_Cols - 1;
884    XWin->cursor_row = r + XWin->scroll_r1;
885    XWin->cursor_col = c;
886    vterm_goto_rc (r, c);
887    if (Performing_Update) return;
888    show_cursor ();
889 }
890 
891 /*}}}*/
892 
893 #define UNUSED_XTERM_FUNCTIONS 0
894 #if UNUSED_XTERM_FUNCTIONS /*{{{*/
895 
JX_begin_insert(void)896 static void JX_begin_insert(void) /*{{{*/
897 {
898    XEvent ev;
899 
900    if (No_XEvents) return;
901    hide_cursor ();
902    copy_rect(XWin->cursor_col, XWin->cursor_row, JX_Screen_Cols - 1, XWin->cursor_row + 1,
903 	     XWin->cursor_col + 1, XWin->cursor_row);
904    XWin->insert_mode = 1;
905 
906    /* The noexpose events really mess up input pending timing.
907       Stop them now. */
908    XFlush(This_XDisplay);
909    if (!XPeekEvent(This_XDisplay, &ev) || (ev.type != NoExpose)) return;
910    XNextEvent(This_XDisplay, &ev);
911 }
912 
913 /*}}}*/
914 
JX_end_insert(void)915 static void JX_end_insert(void) /*{{{*/
916 {
917    XWin->insert_mode = 0;
918 }
919 
920 /*}}}*/
921 
JX_delete_char(void)922 static void JX_delete_char (void) /*{{{*/
923 {
924    copy_rect(XWin->cursor_col + 1, XWin->cursor_row, JX_Screen_Cols, XWin->cursor_row + 1,
925 	     XWin->cursor_col, XWin->cursor_row);
926 }
927 
928 /*}}}*/
929 
JX_erase_line(void)930 static void JX_erase_line(void) /*{{{*/
931 {
932    if (XWin == NULL) return;
933    blank_rect(0, XWin->cursor_row, JX_Screen_Cols, XWin->cursor_row + 1);
934 }
935 
936 /*}}}*/
937 
938 /* This function is called assuming that cursor is in correct
939    position */
JX_putchar(char ch)940 static void JX_putchar(char ch) /*{{{*/
941 {
942    static int k = 0;
943    char s[2];
944 
945    if (ch == '\b')
946      {
947 	ch = ' ';
948 	if (XWin->cursor_col == 0) return;
949 	XWin->cursor_col--;
950      }
951    if(k == 0 && (iskanji(ch)))
952      {
953 	k = ch;
954 	return;
955      }
956    else if(k != 0)
957      {
958 	s[0] = k;
959 	s[1] = ch;
960 	if (Rev_Vid_Flag != JNORMAL_COLOR)
961 	  {
962 	     tt_normal_video();
963 	  }
964 	tt_write(s, 2);
965 	k = 0;
966 	show_cursor();
967 	return;
968      }
969 
970    if (Rev_Vid_Flag != JNORMAL_COLOR) JX_normal_video ();
971    tt_write(&ch, 1);
972    show_cursor ();
973 }
974 
975 /*}}}*/
976 
977 /*}}}*/
978 #endif				       /* UNUSED_XTERM_FUNCTIONS */
979 
980 /* Must respect scrolling region */
JX_delete_nlines(int n)981 static void JX_delete_nlines(int n) /*{{{*/
982 {
983    int r1, r2;
984 
985    vterm_delete_nlines (n);
986 
987    if (No_XEvents || (XWin->window_mapped == 0))
988      return;
989 
990    r1 = XWin->cursor_row;
991    r2 = XWin->scroll_r2;
992 
993    if (r1 <= r2 - n) copy_rect(0, r1 + n, JX_Screen_Cols, r2 + 1,
994 			       0, r1);
995 
996    r2++;
997    blank_rect(0, r2 - n, JX_Screen_Cols, r2);
998 }
999 
1000 /*}}}*/
1001 
JX_reverse_index(int n)1002 static void JX_reverse_index(int n) /*{{{*/
1003 {
1004    int r1, r2;
1005 
1006    vterm_reverse_index (n);
1007 
1008    if (No_XEvents || (XWin->window_mapped == 0))
1009      return;
1010 
1011    r1 = XWin->scroll_r1;
1012    r2 = XWin->scroll_r2;
1013 
1014    if (r2 >= r1 + n) copy_rect(0, r1, JX_Screen_Cols, r2 - n + 1,
1015 			       0, r1 + n);
1016 
1017    blank_rect(0, r1, JX_Screen_Cols, r1 + n);
1018 }
1019 
1020 /*}}}*/
1021 
JX_beep(void)1022 static void JX_beep(void) /*{{{*/
1023 {
1024    GC gc;
1025    XGCValues gcv;
1026 
1027    if (No_XEvents) return;
1028    flush_input();
1029    if (JX_Ignore_Beep & 0x1) XBell (This_XDisplay, 50);
1030 
1031    /* visible bell */
1032 
1033    if (JX_Ignore_Beep & 0x2)
1034      {
1035 	gc = XCreateGC(This_XDisplay, This_XWindow, 0, &gcv);
1036 
1037         XSetState(This_XDisplay, gc,
1038 		  WhitePixel (This_XDisplay, This_XScreen),
1039                   BlackPixel(This_XDisplay, This_XScreen),
1040 		  GXinvert, AllPlanes);
1041 
1042         XFillRectangle (This_XDisplay, This_XWindow, gc,
1043                         0, 0,
1044 			XWin->font_width * JX_Screen_Cols,
1045 			XWin->font_height * JX_Screen_Rows);
1046 
1047         XFlush (This_XDisplay);
1048 
1049 	/* I attempted to put a pause in here but it was too slow. */
1050 
1051         XFillRectangle (This_XDisplay, This_XWindow, gc,
1052                         0, 0,
1053 			XWin->font_width * JX_Screen_Cols,
1054 			XWin->font_height * JX_Screen_Rows);
1055 
1056 	XFreeGC(This_XDisplay, gc);
1057      }
1058    XFlush (This_XDisplay);
1059 }
1060 
1061 /*}}}*/
1062 
JX_del_eol(void)1063 static void JX_del_eol(void) /*{{{*/
1064 {
1065    vterm_del_eol ();
1066 
1067    if (No_XEvents || (XWin->window_mapped == 0))
1068      return;
1069 
1070    blank_rect(XWin->cursor_col, XWin->cursor_row, JX_Screen_Cols, XWin->cursor_row + 1);
1071 }
1072 
1073 /*}}}*/
1074 
JX_reverse_video(int color)1075 static void JX_reverse_video(int color) /*{{{*/
1076 {
1077    if ((color < 0) || (color > JMAX_COLORS))
1078      return;
1079 
1080    if (XWin == NULL) return;
1081    Rev_Vid_Flag = color;
1082    XWin->current_gc[0] = XWin->text_gc[color].gc[0];
1083    XWin->current_gc[1] = XWin->text_gc[color].gc[1];
1084    XWin->current_gc[2] = XWin->text_gc[color].gc[2];
1085    vterm_reverse_video (color);
1086 }
1087 
1088 /*}}}*/
1089 
JX_normal_video(void)1090 static void JX_normal_video(void) /*{{{*/
1091 {
1092    JX_reverse_video (JNORMAL_COLOR);
1093 }
1094 
1095 /*}}}*/
1096 
send_attr_str(unsigned short * s,unsigned short * smax)1097 static void send_attr_str(unsigned short *s, unsigned short *smax) /*{{{*/
1098 {
1099    unsigned char out[250], ch, attr, *p;
1100    register unsigned short sh;
1101 
1102    p = out;
1103    while (s < smax)
1104      {
1105 	sh = (unsigned short) *s++;
1106 	ch = sh & 0xFF;
1107 	attr = sh >> 8;
1108 
1109 	/* Make sure we strip the ACS bit since we do not do that yet. */
1110 	attr &= 0x7F;
1111 
1112 	if ((attr == 0) && (Rev_Vid_Flag != 0))
1113 	  {
1114 	     if (p != out)
1115 	       {
1116 		  *p = 0;
1117 		  JX_write_string ((char *) out);
1118 		  p = out;
1119 	       }
1120 	     JX_normal_video ();
1121 	  }
1122 	else if ((attr != 0) && (Rev_Vid_Flag != attr))
1123 	  {
1124 	     if (p != out)
1125 	       {
1126 		  *p = 0;
1127 		  JX_write_string ((char *) out);
1128 		  p = out;
1129 	       }
1130 	     JX_reverse_video(attr);
1131 	  }
1132 	if (iskanji(ch))
1133 	  {
1134 	     *p++ = ch;
1135 	     ch = (*s++ & 0xFF);
1136 	  }
1137 	*p++ = ch;
1138      }
1139    *p = 0;
1140    if (p != out) JX_write_string ((char *) out);
1141    /* if (Rev_Vid_Flag) tt_normal_video(); */
1142 }
1143 
1144 /*}}}*/
1145 
1146 #define SPACE_CHAR (32 | (JNORMAL_COLOR << 8))
1147 
forward_cursor(int n,int row)1148 static void forward_cursor (int n, int row) /*{{{*/
1149 {
1150    JX_goto_rc (row, XWin->cursor_col + n);
1151 }
1152 
1153 /*}}}*/
1154 
JX_smart_puts(unsigned short * neww,unsigned short * oldd,int len,int row)1155 static void JX_smart_puts(unsigned short *neww,unsigned short *oldd, int len, int row) /*{{{*/
1156 {
1157    register unsigned short *p, *q, *qmax, *pmax, *buf;
1158    unsigned short buffer[256];
1159    int n_spaces;
1160    unsigned short *space_match, *last_buffered_match;
1161 
1162    q = oldd; p = neww;
1163    qmax = oldd + len;
1164    pmax = p + len;
1165 
1166    /* Find out where to begin --- while they match, we are ok */
1167    for (;;)
1168      {
1169 	if (q == qmax) return;
1170 	if (*q != *p) break;
1171 	if(iskanji(*p & 0xff))         /* KANJI ? */
1172 	  {
1173 	     if(*(q+1) != *(p+1))
1174 	       {
1175 		  break;
1176 	       }
1177 	     else
1178 	       {
1179 		  q++; p++;       /* skip 2nd byte of kanji code */
1180 	       }
1181 	  }
1182 	q++; p++;
1183      }
1184 
1185    /*position the cursor */
1186    JX_goto_rc (row, (int) (p - neww));
1187 
1188    /* Find where the last non-blank character on old/new screen is */
1189 
1190    while (qmax > q)
1191      {
1192 	qmax--;
1193 	if (*qmax != SPACE_CHAR)
1194 	  {
1195 	     qmax++;
1196 	     break;
1197 	  }
1198      }
1199    /* if (*qmax != SPACE_CHAR) qmax++; */
1200    while (pmax > p)
1201      {
1202 	pmax--;
1203 	if (*pmax != SPACE_CHAR)
1204 	  {
1205 	     pmax++;
1206 	     break;
1207 	  }
1208      }
1209 
1210    last_buffered_match = buf = buffer;		       /* buffer is empty */
1211 
1212    /* loop using overwrite then skip algorithm until done */
1213    while (1)
1214      {
1215 	/* while they do not match and we do not hit a space, buffer them up */
1216 	n_spaces = 0;
1217 	while (p < pmax)
1218 	  {
1219 	     if ((*q == SPACE_CHAR) && (*p == SPACE_CHAR))
1220 	       {
1221 		  /* If *q is not a space, we would have to overwrite it.
1222 		   * However, if *q is a space, then while *p is also one,
1223 		   * we only need to skip over the blank field.
1224 		   */
1225 		  space_match = p;
1226 		  p++; q++;
1227 		  while ((p < pmax)
1228 			 && (*p == SPACE_CHAR) && (*q == SPACE_CHAR))
1229 		    {
1230 		       p++;
1231 		       q++;
1232 		    }
1233 		  n_spaces = (int) (p - space_match);
1234 		  break;
1235 	       }
1236 	     if(iskanji(*p & 0xff))
1237 	       {
1238 		  if(*q == *p && *(p+1) == *(q+1)) break;
1239 		  else
1240 		    {
1241 		       *buf++ = *p++;
1242 		       q++;
1243 		    }
1244 	       }
1245 	     else if (*q == *p) break;
1246 	     *buf++ = *p++;
1247 	     q++;
1248 	  }
1249 	*buf = 0;
1250 
1251 	if (buf != buffer) send_attr_str (buffer, buf);
1252 	buf = buffer;
1253 
1254 	if (n_spaces && (p < pmax))
1255 	  {
1256 	     forward_cursor (n_spaces, row);
1257 	  }
1258 
1259 	/* Now we overwrote what we could and cursor is placed at position
1260 	 * of a possible match of new and old.  If this is the case, skip
1261 	 * some more.
1262 	 */
1263 
1264 	while ((p < pmax) && (*p == *q))
1265 	  {
1266 	     if(iskanji(*p))
1267 	       {
1268 		  if((*(p+1) & 0xff) == (*(q+1) & 0xff))
1269 		    {
1270 		       *buf++ = *p++;
1271 		       q++;
1272 		    }
1273 		  else
1274 		    break;
1275 	       }
1276 	     *buf++ = *p++;
1277 	     q++;
1278 	  }
1279 
1280 	last_buffered_match = buf;
1281 	if (p >= pmax) break;
1282 
1283 	/* jump to new position is it is greater than 5 otherwise
1284 	 * let it sit in the buffer and output it later.
1285 	 */
1286 	if ((int) (buf - buffer) >= 5)
1287 	  {
1288 	     forward_cursor (buf - buffer, row);
1289 	     last_buffered_match = buf = buffer;
1290 	  }
1291      }
1292    if (buf != buffer)
1293      {
1294 	if (q < qmax)
1295 	  {
1296 	     if ((buf == last_buffered_match)
1297 		 && ((int) (buf - buffer) >= 5))
1298 	       {
1299 		  forward_cursor (buf - buffer, row);
1300 	       }
1301 	     else
1302 	       {
1303 		  *buf = 0;
1304 		  send_attr_str (buffer, buf);
1305 	       }
1306 	  }
1307      }
1308    if (q < qmax) JX_del_eol ();
1309 }
1310 
1311 /*}}}*/
1312 
cover_exposed_area(int x,int y,int width,int height,int count)1313 static void cover_exposed_area (int x, int y, int width, int height, int count) /*{{{*/
1314 {
1315    unsigned short *s, *smax;
1316    int row, save_row, save_col, max_col, max_row, col;
1317 
1318    Performing_Update++;
1319    VTerm_Suspend_Update++;
1320    hide_cursor ();
1321    save_row = XWin->cursor_row;
1322    save_col = XWin->cursor_col;
1323    col = (x - XWin->border) / XWin->font_width;
1324    row = (y - XWin->border) / XWin->font_height;
1325 
1326    max_col = 2 + col + width / XWin->font_width;
1327    max_row = 2 + row + height / XWin->font_height;
1328    if (max_col > JX_Screen_Cols) max_col = JX_Screen_Cols;
1329    if (max_row > JX_Screen_Rows) max_row = JX_Screen_Rows;
1330 
1331    while (row < max_row)
1332      {
1333 	JX_goto_rc (row, col);
1334 	s = VTerm_Display [row];
1335 	smax = s + max_col;
1336 	send_attr_str(s + col, smax);
1337 	row++;
1338      }
1339    JX_goto_rc (save_row, save_col);
1340    Performing_Update--;
1341 
1342    if (count == 0) show_cursor ();
1343 
1344    VTerm_Suspend_Update--;
1345 }
1346 
1347 /*}}}*/
1348 
1349 #include "xkeys.c"
1350 
1351 /* Return 1 if event is listed in the switch or zero otherwise.  The switch
1352  * events are considered harmless--- that is, processing them does not really
1353  * interfere with internal JED state (redisplay, etc...).  More bluntly,
1354  * harmless means that the events can be processesed while checking for
1355  * pending input.
1356  */
x_handle_harmless_events(XEvent * report)1357 static int x_handle_harmless_events (XEvent *report) /*{{{*/
1358 {
1359    switch (report->type)
1360      {
1361       case EnterNotify:
1362 	toggle_cursor(report->xcrossing.focus);
1363 	break;
1364 
1365       case LeaveNotify:
1366 	/* toggle_cursor(0); */
1367 	break;
1368 
1369       case UnmapNotify:
1370 	XWin->window_mapped = 0;
1371 	break;
1372       case MapNotify:
1373 	XWin->window_mapped = 1;
1374 	break;
1375 
1376       case FocusIn:
1377 	toggle_cursor(1);
1378 #ifdef XJED_USE_R6IM
1379 	if (NULL != R6IM_Xic)
1380 	  XSetICFocus (R6IM_Xic);
1381 #endif
1382 	Check_Buffers_Pending = 1;
1383 	break;
1384 
1385       case FocusOut:
1386 	toggle_cursor(0);
1387 #ifdef XJED_USE_R6IM
1388 	if (NULL != R6IM_Xic)
1389 	  XUnsetICFocus (R6IM_Xic);
1390 #endif
1391 	break;
1392 
1393       case VisibilityNotify: XWin->visible = report->xvisibility.state;
1394 	break;
1395 
1396       case GraphicsExpose:
1397 	cover_exposed_area (report->xgraphicsexpose.x,
1398 			    report->xgraphicsexpose.y,
1399 			    report->xgraphicsexpose.width,
1400 			    report->xgraphicsexpose.height,
1401 			    report->xgraphicsexpose.count);
1402 	break;
1403 
1404       case ConfigureNotify:
1405 	XWin->width = report->xconfigure.width;
1406 	XWin->height = report->xconfigure.height;
1407 	jed_init_display ();
1408 	jed_redraw_screen (1);
1409 	break;
1410 
1411       case Expose:
1412 	cover_exposed_area (report->xexpose.x,
1413 			    report->xexpose.y,
1414 			    report->xexpose.width,
1415 			    report->xexpose.height,
1416 			    report->xexpose.count);
1417 	break;
1418 
1419       case NoExpose: break;
1420 
1421       case KeyPress:
1422 	/* Just look for Modifier key presses */
1423 #ifdef XJED_USE_R6IM
1424 	if (R6IM_Xic && (R6IM_Input_Style & XIMPreeditPosition))
1425 	  move_input_position ();
1426 #endif
1427 	return IsModifierKey (XLookupKeysym (&report->xkey, 0));
1428 
1429       default:
1430 	/* fprintf(stderr, "harmless: %d\n", report->type); */
1431 	return 0;
1432      }
1433    return 1;
1434 }
1435 
1436 /*}}}*/
1437 
fill_jmouse(JMouse_Type * jmouse,unsigned char type,int x,int y,unsigned long t,unsigned int button,unsigned int state)1438 static void fill_jmouse (JMouse_Type *jmouse, /*{{{*/
1439 			 unsigned char type, int x, int y, unsigned long t,
1440 			 unsigned int button, unsigned int state)
1441 {
1442    unsigned char s;
1443 #if JED_HAS_MULTICLICK
1444    static unsigned long last_press_time;
1445    static unsigned int clicks;
1446    static unsigned int last_button;
1447 
1448    if (type == JMOUSE_DOWN)
1449      {
1450 	if ((last_button == button)
1451 	    && (last_press_time + JX_MultiClick_Time > t))
1452 	  {
1453 	     clicks++;
1454 	     if (clicks == 2)
1455 	       type = JMOUSE_DOUBLE_CLICK;
1456 	     else
1457 	       type = JMOUSE_TRIPLE_CLICK;
1458 	  }
1459 	else
1460 	  {
1461 	     clicks = 1;
1462 	     last_button = button;
1463 	  }
1464 	last_press_time = t;
1465      }
1466    else if ((clicks > 1) && (last_button == button))
1467      {
1468 	/* Last was a multi-click.  Ignore this event. */
1469 	type = JMOUSE_IGNORE_EVENT;
1470      }
1471 #endif
1472    jmouse->type = type;
1473    jmouse->x = 1 + (x - XWin->border) / XWin->font_width;
1474 
1475    if (y < XWin->border) jmouse->y = 0;
1476    else jmouse->y = 1 + (y - XWin->border) / XWin->font_height;
1477 
1478    if (button == Button1) jmouse->button = JMOUSE_BUTTON_1;
1479    else if (button == Button2) jmouse->button = JMOUSE_BUTTON_2;
1480    else jmouse->button = JMOUSE_BUTTON_3;
1481 
1482    s = 0;
1483    if (state & Button1Mask) s |= JMOUSE_BUTTON_1;
1484    if (state & Button2Mask) s |= JMOUSE_BUTTON_2;
1485    if (state & (Button3Mask|Button4Mask|Button5Mask))
1486      s |= JMOUSE_BUTTON_3;
1487    if (state & ShiftMask) s |= JMOUSE_SHIFT;
1488    if (state & ControlMask) s |= JMOUSE_CTRL;
1489 
1490    jmouse->state = s;
1491 }
1492 
1493 /*}}}*/
1494 
1495 #define R6IM_KEYINPUT_BUFFER_SIZE 60
1496 
1497 /* if force is true, wait for an event.  If force is false, only
1498  *  process events that exist.  This will return either when there
1499  *  are no more events or a key/mouse event is processed returning
1500  *  1 in the process */
X_process_events(int force,char * buf,unsigned int buflen,int * n_chars)1501 static int X_process_events (int force, char *buf, unsigned int buflen,
1502 			     int *n_chars) /*{{{*/
1503 {
1504    XEvent report;
1505    JMouse_Type jmouse;
1506    int ch1;
1507    int block_expose = 0;
1508    char *bufp;
1509    KeySym ks = 0;
1510    int esc = 27;
1511 
1512    Window root, child;
1513    int posx, posy, rootx, rooty;
1514    unsigned int keys_buttons;
1515    int last_x, last_y;
1516    static int last_event, last_motion_down_button;
1517    static unsigned int motion_state;
1518 
1519    int width, height;
1520 
1521    while (force || XPending(This_XDisplay))
1522      {
1523 	XNextEvent(This_XDisplay, &report);
1524 	Current_Event = report;
1525 
1526 	switch  (report.type)
1527 	  {
1528 	   case ClientMessage:
1529 	     if ((report.xclient.format == 32) &&
1530 		 ((Atom) report.xclient.data.l[0] == This_X_Window.wm_del_win))
1531 	       exit_jed ();
1532 	     break;
1533 
1534 	   case MotionNotify:
1535 
1536 	     /* Make sure we get the last event of this type */
1537 	     while (XCheckMaskEvent (This_XDisplay, ButtonMotionMask, &report))
1538 	       ;
1539 
1540 	     if (!XQueryPointer(This_XDisplay, report.xmotion.window,
1541 				&root, &child, &rootx, &rooty, &posx, &posy,
1542 				&keys_buttons)) break;
1543 
1544 	     /* This will ensure that modifier keys are not pressed while
1545 	        we are in motion. */
1546 
1547 	     if ((last_event == MotionNotify)
1548 		 && (motion_state != keys_buttons))
1549 	       break;
1550 
1551 	     motion_state = keys_buttons;
1552 
1553 	     last_x = jmouse.x;
1554 	     last_y = jmouse.y;
1555 
1556 	     fill_jmouse (&jmouse, JMOUSE_DRAG,
1557 			  posx, posy, report.xmotion.time,
1558 			  last_motion_down_button, keys_buttons);
1559 
1560 	     if ((last_x == jmouse.x) && (last_y == jmouse.y)) break;
1561 	     if (-1 == (ch1 = jed_mouse_add_event (&jmouse)))
1562 	       break;		       /* queue full */
1563 
1564 	     /* return ESC ^@ */
1565 	     *buf++ = esc; *buf++ = 0; *buf++ = ch1;
1566 	     *n_chars = 3;
1567 
1568 	     last_event = MotionNotify;
1569 	     return 1;
1570 
1571 	   case Expose:
1572 
1573 	     if (block_expose == 0) cover_exposed_area (report.xexpose.x,
1574 							report.xexpose.y,
1575 							report.xexpose.width,
1576 							report.xexpose.height,
1577 							report.xexpose.count);
1578 	     else
1579 	       {
1580 		  if (report.xexpose.count == 0)
1581 		    {
1582 		       jed_redraw_screen (1);
1583 		       block_expose = 0;
1584 		    }
1585 	       }
1586 #ifdef XJED_USE_R6IM
1587 	     if (R6IM_Input_Style & XIMPreeditArea)
1588 	       {
1589 		  set_geometry (&report, XIMPreeditArea, XNPreeditAttributes);
1590 		  set_geometry (&report, XIMStatusArea, XNStatusAttributes);
1591 	       }
1592 #endif
1593 	     break;
1594 
1595 	   case ConfigureNotify:
1596 	     width = report.xconfigure.width;
1597 	     height = report.xconfigure.height;
1598 	     if ((width != XWin->width) ||
1599 		 (height != XWin->height))
1600 	       {
1601 		  XWin->width = width;
1602 		  XWin->height = height;
1603 		  jed_init_display ();
1604 		  jed_redraw_screen (0);
1605 		  block_expose = -1;
1606 	       }
1607 #ifdef XJED_USE_R6IM
1608 	     if (R6IM_Input_Style & XIMPreeditArea)
1609 	       {
1610 		  set_geometry (&report, XIMPreeditArea, XNPreeditAttributes);
1611 		  set_geometry (&report, XIMStatusArea, XNStatusAttributes);
1612 	       }
1613 #endif
1614 	     break;
1615 
1616 	   case ButtonPress:
1617 	     /* Prohibit dragging more than one button at a time. */
1618 	     if (last_event == MotionNotify) break;
1619 	     /* drop */
1620 
1621 	   case ButtonRelease:
1622 	     if ((last_event == MotionNotify) &&
1623 		 (report.xbutton.button != (unsigned int) last_motion_down_button))
1624 	       break;
1625 
1626 	     last_event = 0;
1627 
1628 	     fill_jmouse (&jmouse,
1629 			  ((report.type == ButtonRelease) ? JMOUSE_UP : JMOUSE_DOWN),
1630 			  report.xbutton.x, report.xbutton.y, report.xbutton.time,
1631 			  report.xbutton.button, report.xbutton.state);
1632 
1633 	     if (-1 == (ch1 = jed_mouse_add_event (&jmouse)))
1634 	       break;		       /* queue full */
1635 
1636 	     if ((report.type == ButtonPress)
1637 		 && (0 == (report.xbutton.state
1638 			   & (Button1Mask|Button2Mask|Button3Mask
1639 			      |Button4Mask|Button5Mask))))
1640 	       last_motion_down_button = report.xbutton.button;
1641 
1642 	     /* ESC ^@ is a  mouse prefix */
1643 	     *buf++ = esc; *buf++ = 0; *buf++ = ch1;
1644 	     *n_chars = 3;
1645 
1646 	     return 1;
1647 
1648 #if HAS_IBM_NUMLOCK_CODE
1649 	   case KeyRelease:
1650 	     if ((report.xkey.keycode != 98)
1651 # if 0
1652 		 || (0 != strcmp (The_Xserver_Vendor,
1653 				  "International Business Machines"))
1654 # endif
1655 		 )
1656 	       {
1657 		  (void) x_handle_harmless_events (&report);
1658 		  break;
1659 	       }
1660 	     /* Drop */
1661 #endif
1662 	   case KeyPress:
1663 	     bufp = buf;
1664 #ifndef XJED_USE_R6IM
1665 	     *n_chars = XLookupString(&report.xkey, buf, buflen, &ks, NULL);
1666 #else
1667 	     if (!XFilterEvent (&report, report.xkey.window))
1668 	       {
1669 		  Status status_return;
1670 		  if (R6IM_Xic != NULL)
1671 		    *n_chars = XmbLookupString (R6IM_Xic, &report.xkey, buf, buflen,
1672 						&ks, &status_return);
1673 		  else
1674 		    *n_chars = XLookupString(&report.xkey, buf, buflen, &ks, NULL);
1675 
1676 	       }
1677 	     else
1678 	       *n_chars = 0;
1679 #endif
1680 	     ks = ks & 0xFFFF;
1681 	     X_Last_Keysym = ks;
1682 #if USE_NEW_META_CODE
1683 	     if ((*n_chars == 0) && (ks > 0x00FF) && (ks < 0x0FFF))
1684 	       {
1685 		  *n_chars = 1;
1686 		  buf[0] = ks & 0x00FF ;
1687 	       }
1688 #endif
1689 	     if (ks >= 0xFF00)
1690 	       {
1691 		  ks = ks & 0xFF;
1692 
1693 		  switch (report.xkey.state & (ShiftMask|ControlMask))
1694 		    {
1695 		     default:
1696 		       bufp = KeySym_Mapping [ks];
1697 		       break;
1698 
1699 		     case ShiftMask:
1700 		       bufp = Shift_KeySym_Mapping [ks];
1701 		       break;
1702 
1703 		     case ControlMask:
1704 		       bufp = Control_KeySym_Mapping [ks];
1705 		       break;
1706 
1707 		     case ShiftMask|ControlMask:
1708 		       bufp = Control_Shift_KeySym_Mapping [ks];
1709 		       break;
1710 		    }
1711 
1712 		  if (0 != (*n_chars = (int) *bufp++))
1713 		    {
1714 #if USE_NEW_META_CODE
1715 		       if (report.xkey.state & Mod1Mask)
1716 			 {
1717 			    buf[0] = '\033' ;
1718 			    SLMEMCPY (buf + 1, bufp, *n_chars);
1719 			    *n_chars += 1;
1720 			 }
1721 		       else
1722 #endif
1723 			 SLMEMCPY(buf, bufp, *n_chars);
1724 		    }
1725 	       }
1726 	     else if (*n_chars == 1)
1727 	       {
1728 		  if (report.xkey.state & Mod1Mask)
1729 		    {
1730 		       ch1 = *bufp;
1731 #if 0
1732 		       /* Only do this on alphabetic characters.  This
1733 			* is because, e.g., german keyboards use 'Alt-{'
1734 			* to generate the '{' character
1735 			*/
1736 		       if (isalnum (ch1) && (ch1 < 0x80))
1737 			 {
1738 #endif
1739 			    if (X_Alt_Char <= 0) *buf |= 0x80;
1740 			    else
1741 			      {
1742 				 *bufp++ = (unsigned char) X_Alt_Char;
1743 				 *bufp = (unsigned char) ch1;
1744 				 *n_chars = 2;
1745 			      }
1746 #if 0
1747 			 }
1748 #endif
1749 		    }
1750 		  else if (report.xkey.state & ControlMask)
1751 		    {
1752 		       if (*buf == ' ') *buf = 0;
1753 		       else if (*buf == '-') *buf = 0x1F;
1754 		    }
1755 	       }
1756 
1757 	     if (*n_chars == 0) break;
1758 	     return 1;
1759 
1760 	   case SelectionNotify:
1761 	     (void) receive_selection (&report);
1762 	     break;
1763 	   case SelectionClear:
1764 	     SLfree (Selection_Send_Data);   /* NULL ok */
1765 	     Selection_Send_Data = NULL;
1766 	     break;
1767 	   case SelectionRequest:
1768 	     send_selection (&report);
1769 	     break;
1770 
1771 	   default:
1772 	     (void) x_handle_harmless_events (&report);
1773 	  }
1774      }
1775    return 0;
1776 }
1777 
1778 /*}}}*/
1779 
X_read_key(void)1780 static int X_read_key (void) /*{{{*/
1781 {
1782    int nread;
1783    char buf[R6IM_KEYINPUT_BUFFER_SIZE];
1784    (void) X_process_events (1, buf, sizeof (buf), &nread);
1785    if (nread > 1) ungetkey_string(buf + 1, nread - 1);
1786    return (int) *buf;
1787 }
1788 
1789 /*}}}*/
1790 
X_input_pending(void)1791 static int X_input_pending (void) /*{{{*/
1792 {
1793    XEvent ev;
1794    int n;
1795 
1796    if (No_XEvents) return 0;
1797 
1798    n = XPending (This_XDisplay);
1799    if (!n) return (0);
1800 
1801    /* I need some way of getting only kbd events. */
1802    while (n--)
1803      {
1804 	XPeekEvent(This_XDisplay, &ev);
1805 	if (0 == x_handle_harmless_events (&ev)) return 1;
1806 	XNextEvent(This_XDisplay, &ev);
1807      }
1808    return 0;
1809 }
1810 
1811 /*}}}*/
1812 
JX_get_display_size(int * rows,int * cols)1813 static void JX_get_display_size (int *rows, int *cols) /*{{{*/
1814 {
1815    JX_Screen_Cols = (XWin->width - XWin->border) / XWin->font_width;
1816    JX_Screen_Rows = (XWin->height - XWin->border) / XWin->font_height;
1817    *cols = JX_Screen_Cols;
1818    *rows = JX_Screen_Rows;
1819 }
1820 
1821 /*}}}*/
1822 
JX_set_term_vtxxx(int * n)1823 static void JX_set_term_vtxxx (int *n) /*{{{*/
1824 {
1825    (void) n;
1826 }
1827 
1828 /*}}}*/
1829 
JX_narrow_width(void)1830 static void JX_narrow_width (void) /*{{{*/
1831 {
1832 }
1833 
1834 /*}}}*/
1835 
JX_wide_width(void)1836 static void  JX_wide_width (void) /*{{{*/
1837 {
1838 }
1839 
1840 /*}}}*/
1841 
JX_enable_cursor_keys(void)1842 static void JX_enable_cursor_keys(void) /*{{{*/
1843 {
1844 }
1845 
1846 /*}}}*/
1847 
JX_cls(void)1848 static void JX_cls(void) /*{{{*/
1849 {
1850    vterm_cls ();
1851 
1852    if (No_XEvents) return;
1853    if (XWin->window_mapped == 0) return;
1854    XClearWindow(This_XDisplay, This_XWindow);
1855 }
1856 
1857 /*}}}*/
1858 
1859 /* This routine is called from S-Lang inner interpreter.  It serves
1860    as a poor mans version of an interrupt 9 handler */
xjed_check_kbd(void)1861 static void xjed_check_kbd(void) /*{{{*/
1862 {
1863    char buf[R6IM_KEYINPUT_BUFFER_SIZE];
1864    int n;
1865    register char *b, *bmax;
1866 
1867    if (Batch || No_XEvents) return;
1868    while (XPending(This_XDisplay))
1869      {
1870 	if (X_process_events (0, buf, sizeof (buf), &n) == 0) continue;
1871 
1872 	b = buf; bmax = b + n;
1873 	while (b < bmax)
1874 	  {
1875 	     if (*b == Abort_Char)
1876 	       {
1877 		  if (CBuf->user_abort != -1)
1878 		    {
1879 		       if (CBuf->user_abort == 0) SLang_Error = USER_BREAK;
1880 		    }
1881 		  else if (Ignore_User_Abort == 0) SLang_Error = USER_BREAK;
1882 		  if (b != buf) buffer_keystring (buf, (int) (b - buf));
1883 		  SLKeyBoard_Quit = 1;
1884 		  break;
1885 	       }
1886 	     b++;
1887 	  }
1888 	if (!SLKeyBoard_Quit) buffer_keystring (buf, n);
1889      }
1890 }
1891 
1892 /*}}}*/
1893 
xjed_suspend(void)1894 static void xjed_suspend (void) /*{{{*/
1895 {
1896    if (No_XEvents) return;
1897    if (XWin->focus)
1898      {
1899 	/* XIconifyWindow (This_XDisplay, XWin->w, This_XScreen); */
1900 	if (XWin->visible == VisibilityUnobscured) XLowerWindow (This_XDisplay, This_XWindow);
1901 	else XRaiseWindow (This_XDisplay, This_XWindow);
1902      }
1903    else
1904      {
1905 	/* The window doesn't have focus which means that this was most
1906 	 * likely called by pressing Ctrl-Z from another window.
1907 	 */
1908 
1909 	sys_suspend ();
1910      }
1911 }
1912 
1913 /*}}}*/
1914 
load_font(char * font,char * kanji_font,char * roman_font)1915 static int load_font (char *font, char *kanji_font, char *roman_font) /*{{{*/
1916 {
1917    static XFontStruct *xfont, *xkanji_font, *xroman_font;
1918 
1919    xfont = XLoadQueryFont(This_XDisplay, font);
1920    if (xfont == NULL) return 0;
1921 
1922    XWin->font = xfont;
1923    XWin->font_name = font;
1924    XWin->font_height = XWin->font->ascent + XWin->font->descent;
1925    XWin->font_width = XWin->font->max_bounds.width;
1926    XWin->font_base = XWin->font->ascent;
1927 
1928    xkanji_font = XLoadQueryFont(This_XDisplay, kanji_font);
1929    if (xkanji_font == NULL) return 0;
1930 
1931    XWin->kanji_font = xkanji_font;
1932    XWin->kanji_font_name = kanji_font;
1933    XWin->kanji_font_height = XWin->kanji_font->ascent + XWin->kanji_font->descent;
1934    XWin->kanji_font_width = XWin->kanji_font->max_bounds.width;
1935    XWin->kanji_font_base = XWin->kanji_font->ascent;
1936 
1937    xroman_font = XLoadQueryFont(This_XDisplay, roman_font);
1938    if (xroman_font == NULL) return 0;
1939 
1940    XWin->roman_font = xroman_font;
1941    XWin->roman_font_name = roman_font;
1942    XWin->roman_font_height = XWin->roman_font->ascent + XWin->roman_font->descent;
1943    XWin->roman_font_width = XWin->roman_font->max_bounds.width;
1944    XWin->roman_font_base = XWin->roman_font->ascent;
1945 
1946    return 1;
1947 }
1948 
1949 /*}}}*/
1950 
get_xdefaults(void)1951 static void get_xdefaults (void) /*{{{*/
1952 {
1953    XWindow_Arg_Type *xargs = X_Arg_List + XARG_START;  /* skip display, name, etc */
1954 
1955    while (xargs->name != NULL)
1956      {
1957 	if (xargs->dflt == NULL)
1958 	  {
1959 	     xargs++;
1960 	     continue;
1961 	  }
1962 
1963 	if ((xargs->type != VOID_TYPE)
1964 	    && (xargs->value == NULL))
1965 	  {
1966 	     char *p;
1967 
1968 	     /* Note that strings returned by XGetDefault are owned by
1969 	      * Xlib and should not be modified or freed by the client.
1970 	      * However, the solaris folks apparantly are not aware of this
1971 	      * and the following two function calls produce memory leaks.
1972 	      * Sigh.
1973 	      */
1974 	     p = XGetDefault(This_XDisplay, This_App_Name, xargs->name);
1975 
1976 	     if (p == NULL)
1977 	       p = XGetDefault (This_XDisplay, XJED_CLASS, xargs->name);
1978 
1979 	     if (p != NULL)
1980 	       xargs->value = p;
1981 	  }
1982 
1983 	if (xargs->value != NULL)
1984 	  *xargs->dflt = xargs->value;
1985 
1986 	xargs++;
1987      }
1988 }
1989 
1990 /*}}}*/
1991 
set_window_name(char * s)1992 static void set_window_name (char *s) /*{{{*/
1993 {
1994    if (Batch) return;
1995    XStoreName (This_XDisplay, XWin->w, s);
1996 }
1997 
1998 /*}}}*/
1999 
set_icon_name(char * s)2000 static void set_icon_name (char *s) /*{{{*/
2001 {
2002    if (Batch) return;
2003    XSetIconName(This_XDisplay, XWin->w, s);
2004 }
2005 
2006 /*}}}*/
2007 
2008 #if 0
2009 static void set_wm_hints (JXWindow_Type *w, int xpos,  int ypos, unsigned long orflags) /*{{{*/
2010 {
2011    XSizeHints h;
2012    XWMHints h1;
2013    XClassHint ch;
2014 
2015    ch.res_name = "xjed";
2016    ch.res_class = "XJed";
2017 
2018    h.width_inc = w->font_width;
2019    h.height_inc = w->font_height;
2020    h.min_width = 5 * w->font_width + w->border;
2021    h.min_height = 5 * w->font_height + w->border;
2022    h.base_height = 0;
2023    h.base_width = 0;
2024    h.x = xpos; h.y = ypos;
2025    h.height = w->height;
2026    h.width = w->width;
2027 
2028    h.flags = PMinSize | PResizeInc | PBaseSize;
2029    h.flags |= orflags;
2030 
2031    XSetWMNormalHints(This_XDisplay, w->w, &h);
2032 
2033    /* This bit allows me to track the focus.  It is not at all clear from
2034       the documentation. */
2035    h1.input = 1;
2036    h1.flags = InputHint;
2037    XSetWMHints(This_XDisplay, w->w, &h1);
2038 # if 0
2039    XSetClassHint(This_XDisplay, w->w, &ch);
2040 # endif
2041 }
2042 
2043 /*}}}*/
2044 #endif
2045 
alloc_color(char * color_name,XColor * color_info)2046 static int alloc_color(char* color_name, XColor* color_info)
2047 {
2048    static XColor exact_info;
2049 
2050    if (XAllocNamedColor(This_XDisplay, XWin->color_map, color_name, color_info,
2051 			&exact_info))
2052      return color_info->pixel;
2053 
2054    if (0 == strncmp (color_name, "bright", 6))
2055      color_name += 6;
2056 
2057    if (XAllocNamedColor(This_XDisplay, XWin->color_map, color_name, color_info,
2058 			&exact_info))
2059      return color_info->pixel;
2060 
2061    fprintf(stderr, "Can't allocate color %s\n", color_name);
2062    return -1;
2063 }
2064 
2065 /* This parses the colors in the XWin structure and setting
2066    defaults to fg, bg upon failure of either one */
setup_ith_color(int i)2067 static void setup_ith_color (int i) /*{{{*/
2068 {
2069    XColor xcol;
2070    int fg, bg;
2071 
2072    if (!Term_Supports_Color)
2073      return;
2074 
2075    fg = alloc_color(XWin->text_gc[i].fg_name, &xcol);
2076    bg = alloc_color(XWin->text_gc[i].bg_name, &xcol);
2077 
2078    if ((fg < 0) || (bg < 0))
2079      return;
2080 
2081    XWin->text_gc[i].fg = fg;
2082    XWin->text_gc[i].bg = bg;
2083 }
2084 
2085 /*}}}*/
2086 
2087 /* This is used to set the colors in the Win structure and if f is non-zero,
2088  * the previous definitions are freed.  f is 0 when the colors correspond to the
2089  * default. */
2090 
x_set_color_free(int i,char * fgcolor,char * bgcolor,int do_free)2091 static void x_set_color_free (int i, char *fgcolor, char *bgcolor, int do_free) /*{{{*/
2092 {
2093    char *save_fg, *save_bg, *fg, *bg;
2094 
2095    if ((*fgcolor == 0) || !strcmp (fgcolor, "default"))
2096      fgcolor = XWin->text_gc[0].fg_name;
2097 
2098    if ((*bgcolor == 0) || !strcmp (bgcolor, "default"))
2099      bgcolor = XWin->text_gc[0].bg_name;
2100 
2101    if (NULL == (fg = SLmalloc(strlen(fgcolor) + 1)))
2102      return;
2103 
2104    strcpy (fg, fgcolor);
2105    if (NULL == (bg = SLmalloc (strlen(bgcolor) + 1)))
2106      {
2107 	SLfree (fg);
2108 	return;
2109      }
2110    strcpy (bg, bgcolor);
2111 
2112    save_fg = XWin->text_gc[i].fg_name;
2113    XWin->text_gc[i].fg_name = fg;
2114    save_bg = XWin->text_gc[i].bg_name;
2115    XWin->text_gc[i].bg_name = bg;
2116 
2117    setup_ith_color (i);
2118    if (do_free)
2119      {
2120 	if (save_fg != NULL) SLfree (save_fg);
2121 	if (save_bg != NULL) SLfree (save_bg);
2122      }
2123 }
2124 
2125 /*}}}*/
2126 
setup_and_parse_colors(void)2127 static void setup_and_parse_colors (void) /*{{{*/
2128 {
2129    unsigned long fg, bg, tmp;
2130    char *fg_name, *bg_name;
2131 
2132    int i;
2133    GC_Info_Type *d;
2134 
2135    /* Check to see if this is a color display */
2136 
2137    bg = WhitePixel (This_XDisplay, This_XScreen);
2138    fg = BlackPixel (This_XDisplay, This_XScreen);
2139 
2140    fg_name = Default_GC_Info[0].fg_name;
2141    bg_name = Default_GC_Info[0].bg_name;
2142 
2143    XWin->color_map = DefaultColormap (This_XDisplay, This_XScreen);
2144 
2145    if (DisplayCells (This_XDisplay, This_XScreen) > 2)
2146      {
2147 	Term_Supports_Color = 1;
2148      }
2149    else Term_Supports_Color = 0;
2150 
2151    for (i = 0; i < JMAX_COLORS; i++)
2152      {
2153 	d = Default_GC_Info + i;
2154 	/* The assumption here is that ALL colors beyond JNORMAL_COLOR (0)
2155 	 * take reversed fg, bgs.  I really ought to have flags if this is
2156 	 * not the case. */
2157 	d->fg = fg;
2158 	d->bg = bg;
2159 	if (d->fg_name == NULL) d->fg_name = fg_name;
2160 	if (d->bg_name == NULL) d->bg_name = bg_name;
2161 
2162 	if (i == JNORMAL_COLOR)
2163 	  {
2164 	     char *tmp_name;
2165 	     tmp = fg; fg = bg; bg = tmp;
2166 	     tmp_name = fg_name; fg_name = bg_name; bg_name = tmp_name;
2167 	  }
2168 
2169 	x_set_color_free (i, d->fg_name, d->bg_name, 0);
2170      }
2171 }
2172 
2173 /*}}}*/
2174 
set_mouse_color(char * fgc,char * bgc)2175 static void set_mouse_color (char *fgc, char *bgc) /*{{{*/
2176 {
2177    XColor xfg, xbg;
2178 
2179    if (0 == Term_Supports_Color)
2180      return;
2181 
2182    if (alloc_color(fgc, &xfg) < 0)
2183      return;
2184    if (alloc_color(bgc, &xbg) < 0)
2185      return;
2186 
2187    XRecolorCursor (This_XDisplay, XWin->mouse, &xfg, &xbg);
2188 }
2189 
2190 /*}}}*/
2191 
create_needed_gcs(void)2192 static void create_needed_gcs (void) /*{{{*/
2193 {
2194    int i;
2195    XGCValues xgcv, kanji_xgcv, roman_xgcv;
2196    xgcv.font = XWin->font->fid;
2197    kanji_xgcv.font = XWin->kanji_font->fid;
2198    roman_xgcv.font = XWin->roman_font->fid;
2199    for (i = 0; i < JMAX_COLORS; i++)
2200      {
2201 	xgcv.foreground = kanji_xgcv.foreground =
2202 	roman_xgcv.foreground = XWin->text_gc[i].fg;
2203 	xgcv.background = kanji_xgcv.background =
2204 	roman_xgcv.background = XWin->text_gc[i].bg;
2205 
2206 	XWin->text_gc[i].gc[0] = XCreateGC(This_XDisplay, This_XWindow,
2207 					   GCForeground | GCBackground | GCFont,
2208 					   &xgcv);
2209 	XWin->text_gc[i].gc[1] = XCreateGC(This_XDisplay, This_XWindow,
2210 					   GCForeground | GCBackground | GCFont,
2211 					   &kanji_xgcv);
2212 	XWin->text_gc[i].gc[2] = XCreateGC(This_XDisplay, This_XWindow,
2213 					   GCForeground | GCBackground | GCFont,
2214 					   &roman_xgcv);
2215      }
2216 }
2217 
2218 /*}}}*/
2219 
create_XWindow(JXWindow_Type * win)2220 static Window create_XWindow (JXWindow_Type *win) /*{{{*/
2221 {
2222    int bdr, x, y, flags;
2223    unsigned int width, height;
2224    XSizeHints sizehint;
2225    XClassHint xcls;
2226    XWMHints wmhint;
2227    long key_event_type;
2228 
2229    bdr = atoi(This_Border_Width_Name);
2230 
2231    if (This_Geometry == NULL)
2232      This_Geometry = Default_Geometry;
2233 
2234    sizehint.flags = 0;
2235    flags = XParseGeometry (This_Geometry, &x, &y, &width, &height);
2236    if (flags & WidthValue)
2237      {
2238 	sizehint.width = width;
2239 	sizehint.flags |= USSize;
2240      }
2241    else
2242      {
2243 	width = JX_Screen_Cols;
2244      }
2245    if (flags & HeightValue)
2246      {
2247 	sizehint.height = height;
2248 	sizehint.flags |= USSize;
2249      }
2250    else
2251      {
2252 	height = JX_Screen_Rows;
2253      }
2254 
2255    win->height  	= height * win->font_height + 2 * win->border;
2256    win->width		= width  * win->font_width  + 2 * win->border;
2257 
2258    sizehint.height	= win->height;
2259    sizehint.width	= win->width;
2260    sizehint.width_inc	= win->font_width;
2261    sizehint.height_inc	= win->font_height;
2262    sizehint.min_width	= 5 * win->font_width  + win->border;
2263    sizehint.min_height	= 5 * win->font_height + win->border;
2264    sizehint.base_height	= 0;
2265    sizehint.base_width	= 0;
2266 
2267    if (flags & XValue)
2268      {
2269 	if (flags & XNegative)
2270 	  {
2271 	     x += (DisplayWidth (This_XDisplay, This_XScreen)
2272 		   - sizehint.width - 2 * win->border);
2273 	     sizehint.win_gravity = NorthEastGravity;
2274 	  }
2275 	sizehint.x = x;
2276 	sizehint.flags |= USPosition;
2277      }
2278    else	x = 0;
2279 
2280    if (flags & YValue)
2281      {
2282 	if (flags & YNegative)
2283 	  {
2284 	     y += (DisplayHeight (This_XDisplay, This_XScreen)
2285 		   - sizehint.height - 2 * win->border);
2286 	     if ((flags&XValue) && (flags&XNegative))
2287 	       sizehint.win_gravity = SouthEastGravity;
2288 	     else
2289 	       sizehint.win_gravity = SouthWestGravity;
2290 	  }
2291 	sizehint.y = y;
2292 	sizehint.flags |= USPosition;
2293      }
2294    else	y = 0;
2295 
2296    sizehint.flags |= (PMinSize | PResizeInc | PBaseSize);
2297 
2298    /* create and display window */
2299    win->w = XCreateSimpleWindow(This_XDisplay,
2300 				RootWindow(This_XDisplay, This_XScreen),
2301 				x, y,     /* xpos, ypos */
2302 				win->width,     /* width, height */
2303 				win->height,     /* width, height */
2304 				bdr,	       /* border width */
2305 				win->text_gc[JNORMAL_COLOR].fg,
2306 				win->text_gc[JNORMAL_COLOR].bg
2307 				);
2308 
2309    xcls.res_name = This_App_Name;
2310    xcls.res_class = XJED_CLASS;
2311 
2312    wmhint.input = True;		/* track the focus */
2313    if (Iconic != NULL)
2314      wmhint.initial_state = IconicState;
2315    else
2316      wmhint.initial_state = NormalState;
2317 
2318    wmhint.flags = InputHint | StateHint;
2319 
2320    XSetWMProperties (This_XDisplay, win->w, NULL, NULL, NULL, 0,
2321                      &sizehint, &wmhint, &xcls);
2322 
2323    /* Enable the delete window protocol */
2324    win->wm_del_win = XInternAtom (This_XDisplay, "WM_DELETE_WINDOW", False);
2325    XSetWMProtocols (This_XDisplay, win->w, &win->wm_del_win, 1);
2326 
2327    if (NULL == (The_Xserver_Vendor = XServerVendor (This_XDisplay)))
2328      The_Xserver_Vendor = "";
2329 
2330    key_event_type = KeyPressMask;
2331 
2332 #if HAS_IBM_NUMLOCK_CODE
2333    if ((0 == strcmp (The_Xserver_Vendor, "International Business Machines"))
2334        || 0 == strcmp (The_Xserver_Vendor, "Hewlett-Packard Company"))
2335      key_event_type |= KeyReleaseMask;
2336 #endif
2337 
2338    /* select event types */
2339    XSelectInput(This_XDisplay, win->w,
2340 		(ExposureMask | key_event_type
2341 		 | ButtonPressMask | ButtonReleaseMask
2342 		 | StructureNotifyMask
2343 		 | PointerMotionHintMask | ButtonMotionMask
2344 		 | EnterWindowMask
2345 		 /* | LeaveWindowMask */
2346 		 | FocusChangeMask
2347 		 | VisibilityChangeMask)
2348 		);
2349 
2350    if (XWin->mouse) XDefineCursor(This_XDisplay, win->w, XWin->mouse);
2351    return win->w;
2352 }
2353 
2354 /*}}}*/
2355 
x_err_handler(Display * d,XErrorEvent * ev)2356 static int x_err_handler (Display *d, XErrorEvent *ev) /*{{{*/
2357 {
2358    char errmsg[256];
2359    No_XEvents = 1;
2360    XGetErrorText (d, ev->error_code, errmsg, 255);
2361    exit_error (errmsg, 0);
2362    return 1;
2363 }
2364 
2365 /*}}}*/
2366 
x_ioerr_handler(Display * d)2367 static int x_ioerr_handler (Display *d) /*{{{*/
2368 {
2369    No_XEvents = 1;
2370    exit_error("XWindows IO error", 0);
2371    return d == NULL;  /* just use d to avoid a warning */
2372 }
2373 
2374 /*}}}*/
2375 
2376 /* returns socket descriptor */
init_Xdisplay(void)2377 static int init_Xdisplay (void) /*{{{*/
2378 {
2379    char dname[80], *n;
2380 
2381    n = X_Arg_List[XARG_DISPLAY].value;
2382    if (n != NULL)
2383      {
2384 	strncpy (dname, X_Arg_List[XARG_DISPLAY].value, 70);
2385 	dname[70] = 0;
2386 	n = dname;
2387 	while (*n && (*n != ':')) n++;
2388 	if (*n == 0) strcpy(n, ":0.0");
2389 	n = dname;
2390      }
2391 
2392    XSetIOErrorHandler (x_ioerr_handler);
2393 
2394    if ( (This_XDisplay = XOpenDisplay(n)) == NULL )
2395      {
2396   	(void) fprintf( stderr, "XJED: cannot connect to X server %s\n",
2397 		       XDisplayName(n));
2398 	exit( -1 );
2399      }
2400 
2401    XSetErrorHandler (x_err_handler);
2402 #if !SKIP_LOCALE_CODE
2403    setlocale(LC_ALL, "");
2404 #endif
2405 
2406 #ifdef XJED_USE_R6IM
2407    setlocale(LC_ALL, "");
2408 #endif
2409 
2410    if (X_Arg_List[XARG_NAME].value != NULL)
2411      {
2412 	This_App_Name = X_Arg_List[XARG_NAME].value;
2413      }
2414 
2415    XWin = &This_X_Window;
2416    get_xdefaults ();
2417 
2418    XWin->font_name = This_Font_Name;
2419    XWin->kanji_font_name = This_Kanji_Font_Name;
2420    XWin->roman_font_name = This_Roman_Font_Name;
2421 
2422    This_XScreen = DefaultScreen(This_XDisplay);
2423 
2424    if (!load_font(XWin->font_name, XWin->kanji_font_name, XWin->roman_font_name))
2425      {
2426 	(void) fprintf( stderr, "XJED: cannot load font %s, using fixed.\n", XWin->font_name);
2427 	if (!load_font("a14", "k14", "r14"))
2428 	  {
2429 	     (void) fprintf( stderr, "XJED: cannot load fixed font.\n");
2430 	     exit( -1 );
2431 	  }
2432      }
2433 
2434    XWin->text_gc = Default_GC_Info;
2435    setup_and_parse_colors ();		       /* This allocs and parses colors */
2436 
2437    XWin->mouse = XCreateFontCursor (This_XDisplay, XC_xterm);
2438    set_mouse_color (This_MFG, This_MBG);
2439 
2440    This_XWindow = create_XWindow(XWin);
2441 
2442    set_window_name (This_App_Title);
2443    set_icon_name (This_App_Name);
2444 
2445    /* GCs and their colors */
2446    create_needed_gcs ();		       /* This uses info from previous call */
2447 
2448    XWin->current_gc[0] = XWin->text_gc[JNORMAL_COLOR].gc[0];
2449    XWin->current_gc[1] = XWin->text_gc[JNORMAL_COLOR].gc[1];
2450    XWin->current_gc[2] = XWin->text_gc[JNORMAL_COLOR].gc[2];
2451 
2452    XSetFont (This_XDisplay, XWin->current_gc[0], XWin->font->fid);
2453    XSetFont (This_XDisplay, XWin->current_gc[1], XWin->kanji_font->fid);
2454    XSetFont (This_XDisplay, XWin->current_gc[2], XWin->roman_font->fid);
2455 
2456    /* display window */
2457 
2458    XMapWindow(This_XDisplay, This_XWindow);
2459 
2460 #ifdef XJED_USE_R6IM
2461    i18init ();
2462 #endif
2463    Compound_Text_Atom = XInternAtom(This_XDisplay, "COMPOUND_TEXT", False);
2464    Xjed_Prop = XInternAtom(This_XDisplay, "XJED_PROPERTY_TEXT", False);
2465 
2466    return ConnectionNumber (This_XDisplay);
2467 }
2468 
2469 /*}}}*/
2470 
reset_Xdisplay(void)2471 static void reset_Xdisplay (void) /*{{{*/
2472 {
2473    if (This_XDisplay != NULL) XCloseDisplay(This_XDisplay);
2474 }
2475 
2476 /*}}}*/
2477 
2478 #define UPCSE(x)  (((x) <= 'z') && ((x) >= 'a') ? (x) - 32 : (x))
myXstrcmp(char * a,char * b)2479 static int myXstrcmp(char *a, char *b) /*{{{*/
2480 {
2481    register char cha, chb;
2482    /* do simple comparison */
2483 
2484    cha = *a++;  chb = *b++;
2485    if ((cha != chb) && (UPCSE(cha) != UPCSE(chb))) return 0;
2486    while ((cha = *a++), (chb = *b++), (cha && chb) != 0)
2487      {
2488 	if (cha != chb) return 0;
2489      }
2490 
2491    return (cha == chb);
2492 }
2493 
2494 /*}}}*/
2495 
2496 #define STREQS(a, b) myXstrcmp(a, b)
X_eval_command_line(int argc,char ** argv)2497 static int X_eval_command_line (int argc, char **argv) /*{{{*/
2498 {
2499    char *arg;
2500    int i;
2501    XWindow_Arg_Type *opt;
2502 
2503    for (i = 1; i < argc; i++)
2504      {
2505 	arg = argv[i];
2506 	if (*arg != '-') break;
2507 	arg++;
2508 	opt = X_Arg_List;
2509 	while (opt->name != NULL)
2510 	  {
2511 	     if (STREQS(opt->name, arg)
2512 		 || ((opt->name1 != NULL) && STREQS(opt->name1, arg))) break;
2513 	     opt++;
2514 	  }
2515 
2516 	if (opt->name == NULL) break;
2517 
2518 	if (opt->type == VOID_TYPE) opt->value = "on";
2519 	else if (i + 1 < argc)
2520 	  {
2521 	     i++;
2522 	     opt->value = argv[i];
2523 	  }
2524 	else break;
2525      }
2526 
2527    /* Out of this loop, argv[i] is the last unprocessed argument */
2528    return i;
2529 }
2530 
2531 /*}}}*/
2532 
2533 #ifdef XJED_USE_R6IM
move_input_position(void)2534 static void move_input_position (void)
2535 {
2536    XPoint spot;
2537    /* XVaNestedList list; */
2538 
2539    spot.x = XWin->border + XWin->cursor_col * XWin->font_width;
2540    spot.y = XWin->cursor_row * XWin->font_height + XWin->border + XWin->font_base;
2541 
2542    if (R6IM_Preedit_Attr != NULL)
2543      XFree (R6IM_Preedit_Attr);
2544    if (NULL != (R6IM_Preedit_Attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL)))
2545      {
2546 	if (R6IM_Xic != NULL)
2547 	  XSetICValues (R6IM_Xic, XNPreeditAttributes, R6IM_Preedit_Attr, NULL);
2548      }
2549 }
2550 
set_geometry(XEvent * report,XIMStyle style,char * attr)2551 static void set_geometry (XEvent *report, XIMStyle style, char *attr)
2552 {
2553    XVaNestedList list;
2554    static XRectangle ra, *rb;
2555 
2556    if (style == XIMPreeditArea)
2557      ra.width = report->xconfigure.width - (XWin->font_width * 8);
2558    else if (style == XIMStatusArea)
2559      ra.width = XWin->font_width * 8;
2560    /*   ra.width = report->xconfigure.width; */
2561    ra.height = XWin->font_height;
2562    list = XVaCreateNestedList (0, XNAreaNeeded, &ra, NULL);
2563    XSetICValues (R6IM_Xic, attr, list, NULL);
2564    XFree (list);
2565 
2566    rb = &ra;
2567    list = XVaCreateNestedList (0, XNAreaNeeded, rb, NULL);
2568    XGetICValues (R6IM_Xic, attr, list, NULL);
2569    XFree (list);
2570 
2571    rb->x = 0;
2572    if (style == XIMPreeditArea)
2573      {
2574 	rb->x = XWin->font_width * 8;
2575 	rb->y = report->xconfigure.height - rb->height;
2576      }
2577    else if (style == XIMStatusArea)
2578      {
2579 	rb->x = 0;
2580 	rb->y = report->xconfigure.height - rb->height;
2581 
2582      }
2583 
2584    list = XVaCreateNestedList (0, XNArea, rb, NULL);
2585    XSetICValues (R6IM_Xic, attr, list, NULL);
2586    XFree (list);
2587    /*   XFree (rb); */
2588 }
2589 
2590 /*
2591  * This is more or less stolen startight from XFree86 xterm. This should
2592  * support all European type languages.
2593  */
i18init(void)2594 static void i18init (void) /*{{{*/
2595 {
2596    int i;
2597    char *p, *s, *ns, *end, tmp[1024], buf[32];
2598    XIM xim = NULL;
2599    XIMStyles *xim_styles = NULL;
2600    int found;
2601 
2602    setlocale(LC_ALL, "");
2603 
2604    if (R6IM_Input_Method != NULL)
2605      {
2606 	strcpy(tmp, R6IM_Input_Method);
2607 	s=tmp;
2608 	while (*s)
2609 	  {
2610 	     while (*s && (isspace(*s) || (*s == ','))) s++;
2611 	     if (*s == 0) break;
2612 	     end = s;
2613 	     while (*end && (*end != ',')) end++;
2614 	     ns = end;
2615 	     if (*end) ns++;
2616 	     *end-- = 0;
2617 	     while ((end >= s) && isspace(*end)) *end-- = 0;
2618 
2619 	     if (*s)
2620 	       {
2621 		  strcpy(buf, "@im=");
2622 		  strcat(buf, s);
2623 		  if (((p = XSetLocaleModifiers(buf)) != NULL)
2624 		      && *p
2625 		      && (NULL != (xim = XOpenIM(This_XDisplay, NULL, NULL, NULL))))
2626 		    break;
2627 	       }
2628 	     s = ns;
2629 	  }
2630      }
2631 
2632    if ((xim == NULL) && ((p = XSetLocaleModifiers("")) != NULL) && *p)
2633      xim = XOpenIM(This_XDisplay, NULL, NULL, NULL);
2634 
2635    if ((xim == NULL) && ((p = XSetLocaleModifiers("@im=none")) != NULL) && *p)
2636      xim = XOpenIM(This_XDisplay, NULL, NULL, NULL);
2637 
2638    if (xim == NULL)
2639      {
2640 	fprintf(stderr, "Failed to open input method");
2641 	return;
2642      }
2643 
2644    /* Believe it or not, XGetIMValues return NULL upon success */
2645    if ((NULL != XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL))
2646        || (xim_styles == NULL))
2647      {
2648         fprintf(stderr, "Input method doesn't support any style\n");
2649         XCloseIM(xim);
2650         return;
2651      }
2652 
2653    found = 0;
2654    strcpy(tmp, R6IM_Preedit_Type);
2655 
2656    s = tmp;
2657    while (*s && !found)
2658      {
2659 	while (*s && (isspace(*s) || (*s == ','))) s++;
2660 	if (*s == 0) break;
2661 	end = s;
2662 	while (*end && (*end != ',')) end++;
2663 	ns = end;
2664 	if (*ns) ns++;
2665 	*end-- = 0;
2666 	while ((end >= s) && isspace(*end)) *end-- = 0;
2667 
2668         if (!strcmp(s, "OverTheSpot"))
2669 	  R6IM_Input_Style = (XIMPreeditPosition | XIMStatusArea);
2670 	else if (!strcmp(s, "OffTheSpot"))
2671 	  R6IM_Input_Style = (XIMPreeditArea | XIMStatusArea);
2672 	else if (!strcmp(s, "Root"))
2673 	  R6IM_Input_Style = (XIMPreeditNothing | XIMStatusNothing);
2674 
2675 	/* FIXME!!!  (I think)
2676 	 * Examples on the web show testing of bits via & instead of
2677 	 * the == operator.
2678 	 */
2679         for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
2680 	  {
2681 	     if (R6IM_Input_Style == xim_styles->supported_styles[i])
2682 	       {
2683 		  found = 1;
2684 		  break;
2685 	       }
2686 	  }
2687         s = ns;
2688      }
2689    XFree(xim_styles);
2690 
2691    if (found == 0)
2692      {
2693         /* fprintf(stderr, "input method doesn't support my preedit type\n"); */
2694         XCloseIM(xim);
2695         return;
2696      }
2697 
2698     /*
2699      * This program only understands the Root preedit_style yet
2700      * Then misc.preedit_type should default to:
2701      *          "OverTheSpot,OffTheSpot,Root"
2702      *  /MaF
2703      */
2704 #if 0
2705    if (R6IM_Input_Style != (XIMPreeditNothing | XIMStatusNothing))
2706      {
2707         fprintf(stderr,"This program only supports the 'Root' preedit type\n");
2708         XCloseIM(xim);
2709         return;
2710      }
2711 #else
2712    if (R6IM_Input_Style == (XIMPreeditNothing | XIMStatusNothing))/* "Root" */
2713      R6IM_Xic = XCreateIC(xim, XNInputStyle, R6IM_Input_Style,
2714 			  XNClientWindow, This_XWindow,
2715 			  XNFocusWindow, This_XWindow,
2716 			  NULL);
2717    else if (R6IM_Input_Style == (XIMPreeditPosition | XIMStatusArea))/* "OverTheSpot" */
2718      {
2719 	XFontSet fs;
2720 	char **miss, *def;
2721 	int n_miss;
2722 	char *fontlist;
2723 	int font_len;
2724 
2725 	R6IM_Spot.x = 0;
2726 	R6IM_Spot.y = 0;
2727 	/*	R6IM_Spot.x = XWin->border + XWin->cursor_col * XWin->font_width;
2728 	 R6IM_Spot.y = XWin->cursor_row * XWin->font_height + XWin->border + XWin->font_base; */
2729 
2730 	font_len = strlen(This_Font_Name) + strlen(This_Kanji_Font_Name)
2731 	  + strlen(This_Roman_Font_Name) + 3;
2732 
2733 	if (NULL != (fontlist = SLmake_nstring (This_Font_Name, font_len)))
2734 	  {
2735 	     strcat(fontlist, ",");
2736 	     strcat(fontlist, This_Kanji_Font_Name);
2737 	     strcat(fontlist, ",");
2738 	     strcat(fontlist, This_Roman_Font_Name);
2739 
2740 	     fs = XCreateFontSet (This_XDisplay, fontlist, &miss, &n_miss, &def);
2741 	     SLfree(fontlist);
2742 
2743 	     R6IM_Preedit_Attr = XVaCreateNestedList (0, XNFontSet, fs,
2744 						      XNSpotLocation, &R6IM_Spot,
2745 						      NULL);
2746 	     R6IM_Xic = XCreateIC(xim, XNInputStyle, R6IM_Input_Style,
2747 				  XNClientWindow, This_XWindow,
2748 				  XNPreeditAttributes, R6IM_Preedit_Attr,
2749 				  XNStatusAttributes, R6IM_Preedit_Attr,
2750 				  NULL);
2751 	  }
2752      }
2753    else if (R6IM_Input_Style == (XIMPreeditArea | XIMStatusArea))/* "OffTheSpot" */
2754      {
2755 	XFontSet fs;
2756 	char **miss, *def;
2757 	int n_miss;
2758 	char *fontlist;
2759 	int font_len;
2760 
2761 	font_len = strlen(This_Font_Name) + strlen(This_Kanji_Font_Name)
2762 	  + strlen(This_Roman_Font_Name) + 3;
2763 
2764 	if (NULL != (fontlist = SLmake_nstring (This_Font_Name, font_len)))
2765 	  {
2766 	     strcat(fontlist, ",");
2767 	     strcat(fontlist, This_Kanji_Font_Name);
2768 	     strcat(fontlist, ",");
2769 	     strcat(fontlist, This_Roman_Font_Name);
2770 
2771 	     fs = XCreateFontSet (This_XDisplay, fontlist, &miss, &n_miss, &def);
2772 	     SLfree(fontlist);
2773 	     R6IM_Preedit_Attr = XVaCreateNestedList (0, XNFontSet, fs,
2774 						      XNSpotLocation, &R6IM_Spot,
2775 						      NULL);
2776 	     R6IM_Xic = XCreateIC(xim, XNInputStyle, R6IM_Input_Style,
2777 				  XNClientWindow, This_XWindow,
2778 				  XNPreeditAttributes, R6IM_Preedit_Attr,
2779 				  XNStatusAttributes, R6IM_Preedit_Attr,
2780 				  NULL);
2781 	  }
2782      }
2783 #endif
2784 
2785    if (NULL == R6IM_Xic)
2786      {
2787 	fprintf(stderr,"Failed to create input context\n");
2788 	XCloseIM(xim);
2789      }
2790 }
2791 
2792 /*}}}*/
2793 #endif
2794 
set_border_color(char * fgc,char * bgc)2795 static void set_border_color (char *fgc, char *bgc) /*{{{*/
2796 {
2797    XColor xfg;
2798    unsigned int bdr = atoi(bgc);
2799 
2800    if (!Term_Supports_Color)
2801      return;
2802 
2803    if (alloc_color(fgc, &xfg) < 0)
2804      return;
2805 
2806    XSetWindowBorder (This_XDisplay, XWin->w, xfg.pixel);
2807    if (bdr < 1000)
2808      XSetWindowBorderWidth (This_XDisplay, XWin->w, bdr);
2809 }
2810 
2811 /*}}}*/
JX_set_mono(int obj_unused,char * unused,SLtt_Char_Type c_unused)2812 static void JX_set_mono (int obj_unused, char *unused, SLtt_Char_Type c_unused)
2813 {
2814    (void) obj_unused;
2815    (void) unused;
2816    (void) c_unused;
2817 }
2818 
JX_set_color(int i,char * what,char * fg,char * bg)2819 static void JX_set_color (int i, char *what, char *fg, char *bg) /*{{{*/
2820 {
2821    if (XWin == NULL)
2822      return;
2823 
2824    if (!Term_Supports_Color) return;
2825 
2826 #if SLANG_VERSION >= 10306
2827    SLsmg_touch_screen ();
2828 #endif
2829 
2830    if (i == -1)
2831      {
2832 	if (!strcmp("mouse", what))
2833 	  {
2834 	     set_mouse_color (fg, bg);
2835 	  }
2836 	else if (!strcmp("border", what))
2837 	  {
2838 	     set_border_color (fg, bg);
2839 	  }
2840 
2841 	return;
2842      }
2843 
2844    x_set_color_free (i, fg, bg, 1);
2845    XSetForeground(This_XDisplay, XWin->text_gc[i].gc[0], XWin->text_gc[i].fg);
2846    XSetForeground(This_XDisplay, XWin->text_gc[i].gc[1], XWin->text_gc[i].fg);
2847    XSetForeground(This_XDisplay, XWin->text_gc[i].gc[2], XWin->text_gc[i].fg);
2848    XSetBackground(This_XDisplay, XWin->text_gc[i].gc[0], XWin->text_gc[i].bg);
2849    XSetBackground(This_XDisplay, XWin->text_gc[i].gc[1], XWin->text_gc[i].bg);
2850    XSetBackground(This_XDisplay, XWin->text_gc[i].gc[2], XWin->text_gc[i].bg);
2851    if (i == JNORMAL_COLOR)
2852      XSetWindowBackground (This_XDisplay, This_XWindow, XWin->text_gc[i].bg);
2853 }
2854 
2855 /*}}}*/
2856 
x_warp_pointer(void)2857 static void x_warp_pointer (void) /*{{{*/
2858 {
2859    X_Warp_Pending = 1;
2860 }
2861 
2862 /*}}}*/
2863 
x_region_2_cutbuffer(void)2864 static void x_region_2_cutbuffer (void) /*{{{*/
2865 {
2866    int nbytes;
2867    char *dat, *kanji_dat;
2868 
2869    dat = make_buffer_substring(&nbytes);
2870    if (dat == NULL) return;
2871 
2872    kanji_dat = KanjiCodeConv(dat, &nbytes, kSLcode, kSLdisplay_code, 0);
2873    XStoreBytes (This_XDisplay, kanji_dat, nbytes);
2874 
2875 #if 0
2876    XChangeProperty (This_XDisplay, DefaultRootWindow (This_XDisplay),
2877 		    XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace,
2878 		    dat, nbytes);
2879 #endif
2880 
2881    if (kanji_dat != dat) SLfree (kanji_dat);
2882    SLfree (dat);
2883 }
2884 
2885 /*}}}*/
2886 
x_insert_cutbuffer(void)2887 static int x_insert_cutbuffer (void) /*{{{*/
2888 {
2889    int nbytes;
2890    char *dat, *kanji_dat;
2891 
2892    CHECK_READ_ONLY
2893      dat = XFetchBytes (This_XDisplay, &nbytes);
2894 
2895    kanji_dat = KanjiCodeConv(dat, &nbytes, kSLdisplay_code, kSLcode, 0);
2896    if (nbytes && (kanji_dat != NULL)) ins_chars ((unsigned char *) kanji_dat, nbytes);
2897    if (dat != NULL) XFree (dat);
2898    return nbytes;
2899 }
2900 
2901 /*}}}*/
2902 
x_insert_selection(void)2903 static int x_insert_selection (void)
2904 {
2905    XConvertSelection (This_XDisplay, XA_PRIMARY, Compound_Text_Atom, Xjed_Prop, This_XWindow,
2906 		      Current_Event.xbutton.time);
2907    return 0;
2908 }
2909 
2910 
receive_selection(XEvent * ev)2911 static int receive_selection (XEvent *ev)
2912 {
2913    Atom actual_type;
2914    int actual_format;
2915    unsigned long nitem, bytes_after;
2916    unsigned char *data, *kanji_data;
2917    char **mbdata;
2918    int nbytes, i, n;
2919    int total_bytes;
2920    XTextProperty tp;
2921 
2922    if (ev->xselection.property == None)
2923      {
2924 	/* Try this */
2925 	(void) x_insert_cutbuffer ();
2926 	return -1;
2927      }
2928 
2929 
2930    if (Success != XGetWindowProperty(This_XDisplay, This_XWindow,
2931 				     ev->xselection.property, 0, 0, False, Compound_Text_Atom,
2932 				     &actual_type, &actual_format, &nitem, &bytes_after, &data))
2933      return -1;
2934    if (Success != XGetWindowProperty(This_XDisplay, This_XWindow,
2935 				     ev->xselection.property, 0, bytes_after, False, Compound_Text_Atom,
2936 				     &actual_type, &actual_format, &nitem, &bytes_after, &data))
2937      return -1;
2938 
2939    if (actual_type != Compound_Text_Atom) return -1;
2940    if (!nitem) return 0;
2941 
2942    XDeleteProperty(This_XDisplay, This_XWindow, ev->xselection.property);
2943 
2944    tp.value = data;
2945    tp.encoding = Compound_Text_Atom;
2946    tp.format = actual_format;
2947    tp.nitems = nitem;
2948 
2949    total_bytes = 0;
2950 
2951    if (Success == XmbTextPropertyToTextList(This_XDisplay, &tp, &mbdata, &n))
2952      {
2953 	for (i=0; i < n; i++)
2954 	  {
2955 	     nbytes = strlen (mbdata[i]);
2956 	     kanji_data = KanjiCodeConv(mbdata[i], &nbytes, EUC, kSLcode, 0);
2957 	     ins_chars ((unsigned char *) kanji_data, nbytes);
2958 	     if(mbdata[i] != kanji_data) SLfree(kanji_data);
2959 	     total_bytes += nbytes;
2960 	  }
2961 	XFreeStringList (mbdata);
2962      }
2963 
2964    if (data != NULL) XFree (data);
2965    return total_bytes;
2966 }
2967 
2968 
2969 
x_region_2_selection(void)2970 static void x_region_2_selection (void)
2971 {
2972    int nbytes;
2973 
2974    Selection_Send_Data = make_buffer_substring (&nbytes);
2975    if (Selection_Send_Data == NULL) return;
2976 
2977    XSetSelectionOwner (This_XDisplay, XA_PRIMARY, This_XWindow, Current_Event.xbutton.time);
2978    if (This_XWindow != XGetSelectionOwner (This_XDisplay, XA_PRIMARY)) return;
2979 }
2980 
send_selection(XEvent * ev)2981 static int send_selection (XEvent *ev)
2982 {
2983    unsigned char *eucdata, *cdata;
2984    int len, n = 1;
2985    XTextProperty tp;
2986    XSelectionEvent sev;
2987 
2988    if (NULL == Selection_Send_Data)
2989      return 0;
2990 
2991    len = strlen (Selection_Send_Data);
2992 
2993    eucdata = KanjiCodeConv (Selection_Send_Data, &len, kSLcode, EUC, 0);
2994 
2995    XmbTextListToTextProperty (This_XDisplay, (char**)&eucdata, 1, XCompoundTextStyle, &tp);
2996 
2997    sev.type = SelectionNotify;
2998    sev.requestor = ev->xselectionrequest.requestor;
2999    sev.selection = ev->xselectionrequest.selection;
3000    sev.target = ev->xselectionrequest.target;
3001    sev.time = ev->xselectionrequest.time;
3002    if(eucdata == Selection_Send_Data)
3003      sev.property = None;
3004    else
3005      {
3006 	sev.property = ev->xselectionrequest.property;
3007 	SLfree(eucdata);
3008      }
3009    XChangeProperty (This_XDisplay, ev->xselectionrequest.requestor,
3010 		    ev->xselectionrequest.property, ev->xselectionrequest.target, tp.format,
3011 		    PropModeReplace, tp.value, tp.nitems);
3012    XSendEvent (This_XDisplay, ev->xselectionrequest.requestor, False, (long)NULL, (XEvent*)&sev);
3013 
3014    return len;
3015 }
3016 
3017 
x_set_keysym(int * np,int * shift,char * str)3018 static void x_set_keysym (int *np, int *shift, char *str) /*{{{*/
3019 {
3020    unsigned int n = (unsigned int) *np;
3021    KeySym_Mapping_Type *map;
3022 
3023    str = SLang_process_keystring (str);
3024    if (str == NULL)
3025      return;
3026 
3027    n &= 0xFF;
3028    switch (*shift)
3029      {
3030       case '$':
3031 	map = Shift_KeySym_Mapping;
3032 	break;
3033 
3034       case '^':
3035 	map = Control_KeySym_Mapping;
3036 	break;
3037 
3038       case '%':
3039 	map = Control_Shift_KeySym_Mapping;
3040 	break;
3041 
3042       default:
3043 	map = KeySym_Mapping;
3044 	break;
3045      }
3046 
3047    SLMEMCPY (map[n], str, MAX_KEYSYM_STRING_LEN);
3048 
3049    *(map[n]) -= 1;
3050 }
3051 
3052 /*}}}*/
3053 
x_server_vendor(void)3054 static char *x_server_vendor (void)
3055 {
3056    return The_Xserver_Vendor;
3057 }
3058 
3059 static SLang_Intrin_Fun_Type sl_x_table[] = /*{{{*/
3060 {
3061    MAKE_INTRINSIC_S("x_set_window_name", set_window_name, VOID_TYPE),
3062    MAKE_INTRINSIC_S("x_set_icon_name", set_icon_name, VOID_TYPE),
3063    MAKE_INTRINSIC("x_warp_pointer", x_warp_pointer, VOID_TYPE, 0),
3064    MAKE_INTRINSIC("x_insert_cutbuffer", x_insert_cutbuffer, INT_TYPE, 0),
3065    /* Prototype: Integer x_insert_cutbuffer ();
3066     * Inserts cutbuffer into the current buffer and returns the number
3067     * of characters inserted.
3068     */
3069    MAKE_INTRINSIC("x_copy_region_to_cutbuffer", x_region_2_cutbuffer, VOID_TYPE, 0),
3070    /*Prototype: Void x_copy_region_to_cutbuffer();
3071     */
3072    MAKE_INTRINSIC("x_insert_selection", x_insert_selection, SLANG_INT_TYPE, 0),
3073    /* Prototype: Integer x_insert_selection ();
3074     * This function is only request selection data to selection owner.
3075     * If Xjed received EVENT, Xjed inserts selection data into the current buffer.
3076     * And returns the number of characters inserted.
3077     */
3078    MAKE_INTRINSIC("x_copy_region_to_selection", x_region_2_selection, VOID_TYPE, 0),
3079    /*Prototype: Void x_copy_region_to_selection();
3080     */
3081    MAKE_INTRINSIC_IIS("x_set_keysym", x_set_keysym, VOID_TYPE),
3082   /*Prototype: Void x_set_keysym (Integer keysym, Integer shift, String str);
3083    *
3084    * This function may be used to assocate a string 'str' with a key
3085    * 'keysym' modified by mask @shift@. Pressing the key associated with
3086    * @keysym@ will then generate the keysequence given by @str@. The
3087    * function keys are mapped to integers in the range @0xFF00@ to @0xFFFF@.
3088    * On most systems, the keys that these mappings refer to are located in
3089    * the file @/usr/include/X11/keysymdef.h@. For example, on my system, the
3090    * keysyms for the function keys @XK_F1@ to @XK_F35@ fall in the range
3091    * @0xFFBE@ to @0xFFE0@. So to make the @F1@ key correspond to the string
3092    * given by the two characters @Ctrl-X@ @Ctrl-C@, simply use:
3093    * @ x_set_keysym (0xFFBE, 0, "^X^C");
3094    * The @shift@ argument is an integer with the following meanings:
3095    * @ 0   : unmodified key
3096    * @ '$'  : shifted
3097    * @ '^'  : control
3098    * Any other value for shift will default to 0 (unshifted).
3099    */
3100    MAKE_INTRINSIC("x_server_vendor", x_server_vendor, STRING_TYPE, 0),
3101    /* Prototype: String x_server_vendor ();
3102     * This function returns the vendor name of the X server.
3103     */
3104    SLANG_END_TABLE
3105 };
3106 
3107 /*}}}*/
3108 
3109 static SLang_Intrin_Var_Type X_Variable_Table [] =
3110 {
3111    MAKE_VARIABLE("ALT_CHAR", &X_Alt_Char, INT_TYPE, 0),
3112    MAKE_VARIABLE("X_LAST_KEYSYM", &X_Last_Keysym, INT_TYPE, 0),
3113    SLANG_END_TABLE
3114 };
3115 
X_init_slang(void)3116 static int X_init_slang (void) /*{{{*/
3117 {
3118    if ((-1 == SLadd_intrin_fun_table (sl_x_table, "XWINDOWS"))
3119        || (-1 == SLadd_intrin_var_table (X_Variable_Table, NULL)))
3120      return -1;
3121    return 0;
3122 }
3123 
3124 /*}}}*/
3125 
X_update_open(void)3126 static void X_update_open (void) /*{{{*/
3127 {
3128    hide_cursor ();
3129    if (Check_Buffers_Pending)
3130      {
3131 	check_buffers();
3132 	Check_Buffers_Pending = 0;
3133      }
3134    Performing_Update = 1;
3135 }
3136 
3137 /*}}}*/
3138 
X_update_close(void)3139 static void X_update_close (void) /*{{{*/
3140 {
3141    Performing_Update = 0;
3142    if (XWin->window_mapped == 0) JWindow->trashed = 1;
3143    if (JWindow->trashed) return;
3144    show_cursor ();
3145    if (X_Warp_Pending)
3146      {
3147 	XWarpPointer (This_XDisplay, None, XWin->w, 0, 0, 0, 0,
3148 		      (XWin->vis_curs_col * XWin->font_width
3149 		       + XWin->border + XWin->font_width / 2),
3150 		      (XWin->vis_curs_row * XWin->font_height
3151 		       + XWin->border + XWin->font_height / 2));
3152 	X_Warp_Pending = 0;
3153      }
3154 
3155 }
3156 
3157 /*}}}*/
3158 
x_define_xkeys(SLKeyMap_List_Type * map)3159 static void x_define_xkeys (SLKeyMap_List_Type *map) /*{{{*/
3160 {
3161    SLkm_define_key ("\033[^D", (FVOID_STAR) scroll_right, map);
3162    SLkm_define_key ("\033[d", (FVOID_STAR) scroll_right, map);
3163    SLkm_define_key ("\033[^C", (FVOID_STAR) scroll_left, map);
3164    SLkm_define_key ("\033[c", (FVOID_STAR) scroll_left, map);
3165    SLkm_define_key ("\033[a", (FVOID_STAR) bob, map);
3166    SLkm_define_key ("\033[^A", (FVOID_STAR) bob, map);
3167    SLkm_define_key ("\033[b", (FVOID_STAR) eob, map);
3168    SLkm_define_key ("\033[^B", (FVOID_STAR) eob, map);
3169    SLkm_define_key ("\033[1~", (FVOID_STAR) bol, map);   /* home */
3170    SLkm_define_key ("\033[4~", (FVOID_STAR) eol, map);   /* end */
3171 }
3172 
3173 /*}}}*/
3174 
JX_reset_video(void)3175 static int JX_reset_video (void) /*{{{*/
3176 {
3177    JX_reset_scroll_region ();
3178    JX_goto_rc (0, 0);
3179    JX_normal_video ();
3180    return vterm_reset_display ();
3181 }
3182 
3183 /*}}}*/
3184 
JX_init_video(void)3185 static int JX_init_video (void) /*{{{*/
3186 {
3187    JX_reset_video ();
3188    if ((JX_Screen_Rows == 0) || (JX_Screen_Cols == 0))
3189      {
3190 	JX_Screen_Cols = 80;
3191 	JX_Screen_Rows = 24;
3192      }
3193 
3194    return vterm_init_display (JX_Screen_Rows, JX_Screen_Cols);
3195 }
3196 
3197 /*}}}*/
3198 
flush_output(void)3199 void flush_output (void) /*{{{*/
3200 {
3201    fflush (stdout);
3202 }
3203 
3204 /*}}}*/
3205 
3206 /* a hook to parse some command line args. */
3207 int (*X_Argc_Argv_Hook)(int, char **) = X_eval_command_line;
3208 
JX_flush_output(void)3209 static int JX_flush_output (void)
3210 {
3211    return 0;
3212 }
3213 
3214 static int JX_Zero = 0;
3215 
JX_get_terminfo(void)3216 static void JX_get_terminfo (void) /*{{{*/
3217 {
3218    SLsmg_Term_Type tt;
3219 
3220    JX_Screen_Cols = 80;
3221    JX_Screen_Rows = 24;
3222 
3223    (void) jed_add_init_slang_hook (X_init_slang);
3224 
3225    /* init hooks */
3226    X_Read_Hook = X_read_key;
3227    X_Input_Pending_Hook = X_input_pending;
3228    X_Update_Open_Hook = X_update_open;
3229    X_Update_Close_Hook = X_update_close;
3230    X_Suspend_Hook = xjed_suspend;
3231    X_Init_Term_Hook = init_Xdisplay;
3232    X_Reset_Term_Hook = reset_Xdisplay;
3233    X_Define_Keys_Hook = x_define_xkeys;
3234    SLang_Interrupt = xjed_check_kbd;
3235 
3236    /* Set this so that main will not try to read from stdin.  It is quite
3237     * likely that this is started from a menu or something.
3238     */
3239    Stdin_Is_TTY = -1;
3240    /* We do not need this since we do not have to worry about incoming
3241     * eight bit escape sequences.
3242     */
3243    DEC_8Bit_Hack = 0;
3244 
3245    memset ((char *) &tt, 0, sizeof (SLsmg_Term_Type));
3246 
3247    tt.tt_normal_video = JX_normal_video;
3248    tt.tt_set_scroll_region = JX_set_scroll_region;
3249    tt.tt_goto_rc = JX_goto_rc;
3250    tt.tt_reverse_index = JX_reverse_index;
3251    tt.tt_reset_scroll_region = JX_reset_scroll_region;
3252    tt.tt_delete_nlines = JX_delete_nlines;
3253    tt.tt_cls = JX_cls;
3254    tt.tt_del_eol = JX_del_eol;
3255    tt.tt_smart_puts = JX_smart_puts;
3256    tt.tt_flush_output = JX_flush_output;
3257    tt.tt_reset_video = JX_reset_video;
3258    tt.tt_init_video = JX_init_video;
3259 
3260    tt.tt_screen_rows = &JX_Screen_Rows;
3261    tt.tt_screen_cols = &JX_Screen_Cols;
3262    tt.tt_term_cannot_scroll = &JX_Term_Cannot_Scroll;
3263    tt.tt_has_alt_charset = &JX_Zero;
3264 
3265    SLsmg_set_terminal_info (&tt);
3266 }
3267 
3268 /*}}}*/
3269 
3270 /* the links to functions and variables here */
3271 void (*tt_beep)(void)  			= JX_beep;
3272 void (*tt_write_string)(char *)  	= JX_write_string;
3273 void (*tt_get_terminfo)(void)  		= JX_get_terminfo;
3274 void (*tt_set_color)(int, char *, char *, char *) = JX_set_color;
3275 void (*tt_set_color_esc)(int, char *);
3276 void (*tt_set_mono) (int, char *, SLtt_Char_Type) = JX_set_mono;
3277 
3278 void (*tt_wide_width)(void)  		= JX_wide_width;
3279 void (*tt_narrow_width)(void)  		= JX_narrow_width;
3280 void (*tt_enable_cursor_keys)(void)  	= JX_enable_cursor_keys;
3281 void (*tt_set_term_vtxxx)(int *)  	= JX_set_term_vtxxx;
3282 void (*tt_get_screen_size)(int *, int *) = JX_get_display_size;
3283 
3284 int *tt_Ignore_Beep  		= &JX_Ignore_Beep;
3285 int *tt_Use_Ansi_Colors  	= &JX_Use_Ansi_Colors;
3286 int *tt_Term_Cannot_Scroll  	= &JX_Term_Cannot_Scroll;
3287 int *tt_Term_Cannot_Insert  	= &JX_Term_Cannot_Insert;
3288 int *tt_Blink_Mode		= &JX_Blink_Mode;
3289 /* int *tt_Baud_Rate               = &JX_Zero; */
3290 
3291 /* Unused but required. */
3292 #ifdef USE_GPM_MOUSE
3293 int (*X_Open_Mouse_Hook)(void);
3294 void (*X_Close_Mouse_Hook)(void);
3295 #endif
3296