term.c 127 KB
Newer Older
1
/* Terminal control module for terminals described by TERMCAP
2 3
   Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2013 Free Software
   Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
Jim Blandy's avatar
Jim Blandy committed
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jim Blandy's avatar
Jim Blandy committed
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
18
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
19

20
/* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>.  */
Jim Blandy's avatar
Jim Blandy committed
21

22
#include <config.h>
23
#include <errno.h>
24 25
#include <fcntl.h>
#include <stdio.h>
26
#include <sys/file.h>
27
#include <sys/time.h>
28
#include <unistd.h>
29

30
#include "lisp.h"
Jim Blandy's avatar
Jim Blandy committed
31
#include "termchar.h"
Paul Eggert's avatar
Paul Eggert committed
32
#include "tparam.h"
33
#include "character.h"
34
#include "buffer.h"
Karl Heuer's avatar
Karl Heuer committed
35 36
#include "charset.h"
#include "coding.h"
Kenichi Handa's avatar
Kenichi Handa committed
37
#include "composite.h"
38
#include "keyboard.h"
Jim Blandy's avatar
Jim Blandy committed
39
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
40 41
#include "disptab.h"
#include "termhooks.h"
Andreas Schwab's avatar
Andreas Schwab committed
42
#include "dispextern.h"
Gerd Moellmann's avatar
Gerd Moellmann committed
43
#include "window.h"
Stefan Monnier's avatar
Stefan Monnier committed
44
#include "keymap.h"
YAMAMOTO Mitsuharu's avatar
YAMAMOTO Mitsuharu committed
45
#include "blockinput.h"
46 47
#include "syssignal.h"
#include "systty.h"
48
#include "intervals.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
49 50 51 52
#ifdef MSDOS
#include "msdos.h"
static int been_here = -1;
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
53

54 55 56 57
#ifdef USE_X_TOOLKIT
#include "../lwlib/lwlib.h"
#endif

58
#include "cm.h"
Andreas Schwab's avatar
Andreas Schwab committed
59 60 61
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
Karl Heuer's avatar
Karl Heuer committed
62

63
#include "menu.h"
Kenichi Handa's avatar
Kenichi Handa committed
64

65 66 67
/* The name of the default console device.  */
#ifdef WINDOWSNT
#define DEV_TTY  "CONOUT$"
68
#include "w32term.h"
69 70 71
#else
#define DEV_TTY  "/dev/tty"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
72

73 74 75
static void tty_set_scroll_region (struct frame *f, int start, int stop);
static void turn_on_face (struct frame *, int face_id);
static void turn_off_face (struct frame *, int face_id);
76
static void tty_turn_off_highlight (struct tty_display_info *);
77 78 79
static void tty_show_cursor (struct tty_display_info *);
static void tty_hide_cursor (struct tty_display_info *);
static void tty_background_highlight (struct tty_display_info *tty);
80
static struct terminal *get_tty_terminal (Lisp_Object, bool);
81 82 83 84
static void clear_tty_hooks (struct terminal *terminal);
static void set_tty_hooks (struct terminal *terminal);
static void dissociate_if_controlling_tty (int fd);
static void delete_tty (struct terminal *);
85 86
static _Noreturn void maybe_fatal (bool, struct terminal *,
				   const char *, const char *, ...)
87 88 89
  ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
static _Noreturn void vfatal (const char *str, va_list ap)
  ATTRIBUTE_FORMAT_PRINTF (1, 0);
90

Gerd Moellmann's avatar
Gerd Moellmann committed
91

92 93
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
94
               FRAME_LINES (XFRAME (selected_frame)) - curY (tty),	\
95 96
               cmputc)

97 98
#define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
#define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
Gerd Moellmann's avatar
Gerd Moellmann committed
99

100
#define OUTPUT_IF(tty, a)                                               \
101 102
  do {                                                                  \
    if (a)                                                              \
103
      OUTPUT (tty, a);							\
104
  } while (0)
105

106
#define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
107

108
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
109

110
/* Chain of all tty device parameters. */
111
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
112

113 114 115 116 117 118 119 120
/* Meaning of bits in no_color_video.  Each bit set means that the
   corresponding attribute cannot be combined with colors.  */

enum no_color_bit
{
  NC_STANDOUT	 = 1 << 0,
  NC_UNDERLINE	 = 1 << 1,
  NC_REVERSE	 = 1 << 2,
121
  NC_ITALIC	 = 1 << 3,
122 123 124
  NC_DIM	 = 1 << 4,
  NC_BOLD	 = 1 << 5,
  NC_INVIS	 = 1 << 6,
125
  NC_PROTECT	 = 1 << 7
126 127
};

Jim Blandy's avatar
Jim Blandy committed
128 129
/* internal state */

130
/* The largest frame width in any call to calculate_costs.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
131

132
static int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
133

Jim Blandy's avatar
Jim Blandy committed
134

135

136
#ifdef HAVE_GPM
137 138
#include <sys/fcntl.h>

139 140
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
141

142
/* Last recorded mouse coordinates.  */
143
static int last_mouse_x, last_mouse_y;
144
#endif /* HAVE_GPM */
145

146
/* Ring the bell on a tty. */
147

148
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
149
tty_ring_bell (struct frame *f)
150 151
{
  struct tty_display_info *tty = FRAME_TTY (f);
152

153 154 155 156 157 158
  if (tty->output)
    {
      OUTPUT (tty, (tty->TS_visible_bell && visible_bell
                    ? tty->TS_visible_bell
                    : tty->TS_bell));
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
159 160 161
    }
}

162 163
/* Set up termcap modes for Emacs. */

164
static void
165
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
166
{
167
  struct tty_display_info *tty = terminal->display_info.tty;
168

169
  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
170
    {
171 172
      if (tty->TS_termcap_modes)
        OUTPUT (tty, tty->TS_termcap_modes);
173
      else
174 175 176 177
        {
          /* Output enough newlines to scroll all the old screen contents
             off the screen, so it won't be overwritten and lost.  */
          int i;
178
          current_tty = tty;
179
          for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
180
            cmputc ('\n');
181 182
        }

183
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
184 185
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
186
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
187 188 189
    }
}

190 191
/* Reset termcap modes before exiting Emacs. */

192
static void
193
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
194
{
195
  struct tty_display_info *tty = terminal->display_info.tty;
196 197

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
198
    {
199 200
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
201 202 203 204
      OUTPUT_IF (tty, tty->TS_end_keypad_mode);
      OUTPUT_IF (tty, tty->TS_cursor_normal);
      OUTPUT_IF (tty, tty->TS_end_termcap_modes);
      OUTPUT_IF (tty, tty->TS_orig_pair);
205
      /* Output raw CR so kernel can track the cursor hpos.  */
206
      current_tty = tty;
207
      cmputc ('\r');
208
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
209 210 211
    }
}

212
/* Flag the end of a display update on a termcap terminal. */
Jim Blandy's avatar
Jim Blandy committed
213

214
static void
215
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
216
{
217
  struct tty_display_info *tty = FRAME_TTY (f);
218

219 220
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
221 222
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
223 224
}

225 226
/* The implementation of set_terminal_window for termcap frames. */

227
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
228
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
229
{
230 231 232 233
  struct tty_display_info *tty = FRAME_TTY (f);

  tty->specified_window = size ? size : FRAME_LINES (f);
  if (FRAME_SCROLL_REGION_OK (f))
234
    tty_set_scroll_region (f, 0, tty->specified_window);
Jim Blandy's avatar
Jim Blandy committed
235 236
}

237 238
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
239 240
{
  char *buf;
241
  struct tty_display_info *tty = FRAME_TTY (f);
242

243
  if (tty->TS_set_scroll_region)
Paul Eggert's avatar
Paul Eggert committed
244
    buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
245 246
  else if (tty->TS_set_scroll_region_1)
    buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
247 248 249
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
250
  else
251
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
252

253
  OUTPUT (tty, buf);
254
  xfree (buf);
255
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
256
}
257

Jim Blandy's avatar
Jim Blandy committed
258

259
static void
260
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
261
{
262 263 264
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
265 266
}

Andreas Schwab's avatar
Andreas Schwab committed
267
void
268
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
269
{
270 271 272
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
273 274
}

275
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
276

277
static void
278
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
279
{
280 281 282
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
283 284
}

285
static void
286
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
287
{
288 289 290
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
291 292
}

293
static void
294
tty_toggle_highlight (struct tty_display_info *tty)
295
{
296
  if (tty->standout_mode)
297
    tty_turn_off_highlight (tty);
298
  else
299
    tty_turn_on_highlight (tty);
300 301
}

Gerd Moellmann's avatar
Gerd Moellmann committed
302 303 304 305

/* Make cursor invisible.  */

static void
306
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
307
{
308
  if (tty->cursor_hidden == 0)
309
    {
310
      tty->cursor_hidden = 1;
311 312 313
#ifdef WINDOWSNT
      w32con_hide_cursor ();
#else
314
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
315
#endif
316
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
317 318 319 320 321 322
}


/* Ensure that cursor is visible.  */

static void
323
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
324
{
325
  if (tty->cursor_hidden)
326
    {
327
      tty->cursor_hidden = 0;
328 329 330
#ifdef WINDOWSNT
      w32con_show_cursor ();
#else
331
      OUTPUT_IF (tty, tty->TS_cursor_normal);
332
      if (visible_cursor)
333
        OUTPUT_IF (tty, tty->TS_cursor_visible);
334
#endif
335
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
336 337 338
}


Jim Blandy's avatar
Jim Blandy committed
339 340 341 342
/* Set standout mode to the state it should be in for
   empty space inside windows.  What this is,
   depends on the user option inverse-video.  */

343 344
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
345 346
{
  if (inverse_video)
347
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
348
  else
349
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
350 351 352 353
}

/* Set standout mode to the mode specified for the text to be output.  */

Andreas Schwab's avatar
Andreas Schwab committed
354
static void
355
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
356
{
357
  if (inverse_video)
358
    tty_turn_on_highlight (tty);
359
  else
360
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
361 362 363
}


Gerd Moellmann's avatar
Gerd Moellmann committed
364 365
/* Move cursor to row/column position VPOS/HPOS.  HPOS/VPOS are
   frame-relative coordinates.  */
Jim Blandy's avatar
Jim Blandy committed
366

367
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
368
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
369
{
370
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
371

372 373
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
374
  if (! tty->costs_set)
375 376
    return;

377 378
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
379
    return;
380
  if (!tty->TF_standout_motion)
381
    tty_background_highlight (tty);
382
  if (!tty->TF_insmode_motion)
383
    tty_turn_off_insert (tty);
384
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
385 386 387 388
}

/* Similar but don't take any account of the wasted characters.  */

389
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
390
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
391
{
392 393
  struct tty_display_info *tty = FRAME_TTY (f);

394 395
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
396
    return;
397
  if (!tty->TF_standout_motion)
398
    tty_background_highlight (tty);
399
  if (!tty->TF_insmode_motion)
400
    tty_turn_off_insert (tty);
401
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
402 403 404 405
}

/* Erase operations */

406 407
/* Clear from cursor to end of frame on a termcap device. */

408
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
409
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
410 411
{
  register int i;
412
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
413

414
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
415
    {
416
      tty_background_highlight (tty);
417
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
418 419 420
    }
  else
    {
421
      for (i = curY (tty); i < FRAME_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
422
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
423 424
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
425 426 427 428
	}
    }
}

429
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
430

431
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
432
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
433
{
434
  struct tty_display_info *tty = FRAME_TTY (f);
435

436
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
437
    {
438
      tty_background_highlight (tty);
439
      OUTPUT (tty, tty->TS_clr_frame);
440
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
441 442 443
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
444 445
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
446 447 448
    }
}

449
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
450 451 452

   Note that the cursor may be moved, on terminals lacking a `ce' string.  */

453
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
454
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
455 456
{
  register int i;
457
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
458

459 460
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
461
  if (! tty->costs_set)
462 463
    return;

464
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
465
    return;
466
  tty_background_highlight (tty);
467
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
468
    {
469
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
470 471 472
    }
  else
    {			/* have to do it the hard way */
473
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
474

Gerd Moellmann's avatar
Gerd Moellmann committed
475
      /* Do not write in last row last col with Auto-wrap on. */
476
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
477 478
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
479 480
	first_unused_hpos--;

481
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
482
	{
483 484 485
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
486
	}
487
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
488 489 490
    }
}

491 492 493 494
/* Buffers to store the source and result of code conversion for terminal.  */
static unsigned char *encode_terminal_src;
static unsigned char *encode_terminal_dst;
/* Allocated sizes of the above buffers.  */
495 496
static ptrdiff_t encode_terminal_src_size;
static ptrdiff_t encode_terminal_dst_size;
497 498 499 500 501

/* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
   Set CODING->produced to the byte-length of the resulting byte
   sequence, and return a pointer to that byte sequence.  */

502
unsigned char *
503
encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
504
{
505
  struct glyph *src_end = src + src_len;
506
  unsigned char *buf;
507 508
  ptrdiff_t nchars, nbytes, required;
  ptrdiff_t tlen = GLYPH_TABLE_LENGTH;
Karl Heuer's avatar
Karl Heuer committed
509
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
510
  Lisp_Object charset_list;
511

512 513
  /* Allocate sufficient size of buffer to store all characters in
     multibyte-form.  But, it may be enlarged on demand if
Kenichi Handa's avatar
Kenichi Handa committed
514 515
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
516 517 518 519
  if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < src_len)
    memory_full (SIZE_MAX);
  required = src_len;
  required *= MAX_MULTIBYTE_LENGTH;
520 521
  if (encode_terminal_src_size < required)
    {
522
      encode_terminal_src = xrealloc (encode_terminal_src, required);
523 524
      encode_terminal_src_size = required;
    }
525

526
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
527

528 529 530
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
531
    {
Kenichi Handa's avatar
Kenichi Handa committed
532 533
      if (src->type == COMPOSITE_GLYPH)
	{
534 535
	  struct composition *cmp IF_LINT (= NULL);
	  Lisp_Object gstring IF_LINT (= Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
536 537 538
	  int i;

	  nbytes = buf - encode_terminal_src;
539 540 541
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
542
	      required = src->slice.cmp.to - src->slice.cmp.from + 1;
543 544 545 546
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
547 548
	      required = cmp->glyph_len;
	      required *= MAX_MULTIBYTE_LENGTH;
549
	    }
Kenichi Handa's avatar
Kenichi Handa committed
550

551
	  if (encode_terminal_src_size - nbytes < required)
Kenichi Handa's avatar
Kenichi Handa committed
552
	    {
553 554 555 556
	      encode_terminal_src =
		xpalloc (encode_terminal_src, &encode_terminal_src_size,
			 required - (encode_terminal_src_size - nbytes),
			 -1, 1);
Kenichi Handa's avatar
Kenichi Handa committed
557 558 559
	      buf = encode_terminal_src + nbytes;
	    }

560
	  if (src->u.cmp.automatic)
561
	    for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
562 563 564 565 566
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
567
		  c = '?';
568 569 570 571 572 573 574 575
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

576 577
		/* TAB in a composition means display glyphs with
		   padding space on the left or right.  */
578 579 580 581 582 583 584 585 586 587 588 589 590 591
		if (c == '\t')
		  continue;
		if (char_charset (c, charset_list, NULL))
		  {
		    if (CHAR_WIDTH (c) == 0
			&& i > 0 && COMPOSITION_GLYPH (cmp, i - 1) == '\t')
		      /* Should be left-padded */
		      {
			buf += CHAR_STRING (' ', buf);
			nchars++;
		      }
		  }
		else
		  c = '?';
592 593 594
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
595
	}
Karl Heuer's avatar
Karl Heuer committed
596
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
597
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
598
	{
599
	  GLYPH g;
600
	  int c IF_LINT (= 0);
601 602
	  Lisp_Object string;

603
	  string = Qnil;
604
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
605

606
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
607
	    {
608
	      /* This glyph doesn't have an entry in Vglyph_table.  */
609 610
	      c = src->u.ch;
	    }
611
	  else
Karl Heuer's avatar
Karl Heuer committed
612
	    {
613
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
614 615
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
616 617

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
618 619
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
620
		c = GLYPH_CHAR (g);
621
	      else
622
		/* We have a string in Vglyph_table.  */
623
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
624
	    }
625

626
	  if (NILP (string))
627
	    {
Kenichi Handa's avatar
Kenichi Handa committed
628
	      nbytes = buf - encode_terminal_src;
629
	      if (encode_terminal_src_size - nbytes < MAX_MULTIBYTE_LENGTH)
Kenichi Handa's avatar
Kenichi Handa committed
630
		{
631 632 633
		  encode_terminal_src =
		    xpalloc (encode_terminal_src, &encode_terminal_src_size,
			     MAX_MULTIBYTE_LENGTH, -1, 1);
Kenichi Handa's avatar
Kenichi Handa committed
634 635
		  buf = encode_terminal_src + nbytes;
		}
636 637
	      if (CHAR_BYTE8_P (c)
		  || char_charset (c, charset_list, NULL))
638
		{
639 640 641
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
642 643 644
		}
	      else
		{
645 646
		  /* C is not encodable.  */
		  *buf++ = '?';
647
		  nchars++;
648 649 650 651 652 653
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
654
		}
655 656 657
	    }
	  else
	    {
658 659 660
	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
661
	      if (encode_terminal_src_size - nbytes < SBYTES (string))
662
		{
663 664 665 666 667
		  encode_terminal_src =
		    xpalloc (encode_terminal_src, &encode_terminal_src_size,
			     (SBYTES (string)
			      - (encode_terminal_src_size - nbytes)),
			     -1, 1);
668
		  buf = encode_terminal_src + nbytes;
669
		}
670
	      memcpy (buf, SDATA (string), SBYTES (string));
671 672
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
673
	    }
Karl Heuer's avatar
Karl Heuer committed
674
	}
675 676 677 678 679 680 681
      src++;
    }

  if (nchars == 0)
    {
      coding->produced = 0;
      return NULL;
Karl Heuer's avatar
Karl Heuer committed
682
    }
683

684 685 686
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
687
    {
688 689
      encode_terminal_dst = xrealloc (encode_terminal_dst,
				      encode_terminal_src_size);
690
      encode_terminal_dst_size = encode_terminal_src_size;
691
    }
692 693 694
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
695
  /* coding->destination may have been reallocated.  */
696 697
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
698

699
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
700 701
}

Jim Blandy's avatar
Jim Blandy committed
702

Miles Bader's avatar
Miles Bader committed
703

704 705
/* An implementation of write_glyphs for termcap frames. */

706
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
707
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
708
{
709 710
  unsigned char *conversion_buffer;
  struct coding_system *coding;
711
  int n, stringlen;
Jim Blandy's avatar
Jim Blandy committed
712

713
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
714

715
  tty_turn_off_insert (tty);
716
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
717

Gerd Moellmann's avatar
Gerd Moellmann committed
718
  /* Don't dare write in last column of bottom line, if Auto-Wrap,
Jim Blandy's avatar
Jim Blandy committed
719
     since that would scroll the whole frame on some terminals.  */
Jim Blandy's avatar
Jim Blandy committed
720

721 722 723
  if (AutoWrap (tty)
      && curY (tty) + 1 == FRAME_LINES (f)
      && (curX (tty) + len) == FRAME_COLS (f))