term.c 114 KB
Newer Older
1
/* Terminal control module for terminals described by TERMCAP
2
   Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1998, 2000, 2001,
Glenn Morris's avatar
Glenn Morris committed
3
                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Glenn Morris's avatar
Glenn Morris committed
4
                 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
5 6 7

This file is part of GNU Emacs.

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

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
19
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
20

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

23
#include <config.h>
Jim Blandy's avatar
Jim Blandy committed
24 25
#include <stdio.h>
#include <ctype.h>
Gerd Moellmann's avatar
Gerd Moellmann committed
26
#include <string.h>
27
#include <errno.h>
28
#include <sys/file.h>
Miles Bader's avatar
Miles Bader committed
29

30
#ifdef HAVE_UNISTD_H
31
#include <unistd.h>
32
#endif
33

34 35 36
#if HAVE_TERMIOS_H
#include <termios.h>		/* For TIOCNOTTY. */
#endif
37 38

#include <signal.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
39
#include <stdarg.h>
40
#include <setjmp.h>
41

42
#include "lisp.h"
Jim Blandy's avatar
Jim Blandy committed
43 44
#include "termchar.h"
#include "termopts.h"
45 46
#include "buffer.h"
#include "character.h"
Karl Heuer's avatar
Karl Heuer committed
47 48
#include "charset.h"
#include "coding.h"
Kenichi Handa's avatar
Kenichi Handa committed
49
#include "composite.h"
50
#include "keyboard.h"
Jim Blandy's avatar
Jim Blandy committed
51
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
52 53
#include "disptab.h"
#include "termhooks.h"
Andreas Schwab's avatar
Andreas Schwab committed
54
#include "dispextern.h"
Gerd Moellmann's avatar
Gerd Moellmann committed
55
#include "window.h"
Stefan Monnier's avatar
Stefan Monnier committed
56
#include "keymap.h"
YAMAMOTO Mitsuharu's avatar
YAMAMOTO Mitsuharu committed
57
#include "blockinput.h"
58 59
#include "syssignal.h"
#include "systty.h"
60
#include "intervals.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
61 62 63 64
#ifdef MSDOS
#include "msdos.h"
static int been_here = -1;
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
65

66 67 68
/* For now, don't try to include termcap.h.  On some systems,
   configure finds a non-standard termcap.h that the main build
   won't find.  */
69 70 71 72
extern void tputs (const char *, int, int (*)(int));
extern int tgetent (char *, const char *);
extern int tgetflag (char *id);
extern int tgetnum (char *id);
73

74
#include "cm.h"
Andreas Schwab's avatar
Andreas Schwab committed
75 76 77
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
Karl Heuer's avatar
Karl Heuer committed
78

79 80 81
#ifndef O_RDWR
#define O_RDWR 2
#endif
Kenichi Handa's avatar
Kenichi Handa committed
82

83 84 85
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
Kenichi Handa's avatar
Kenichi Handa committed
86

87 88 89 90 91 92
/* The name of the default console device.  */
#ifdef WINDOWSNT
#define DEV_TTY  "CONOUT$"
#else
#define DEV_TTY  "/dev/tty"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
93

94 95 96 97 98 99 100 101 102 103
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);
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);
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 *);
104 105 106 107
static void maybe_fatal (int must_succeed, struct terminal *terminal,
			 const char *str1, const char *str2, ...) NO_RETURN;
static void vfatal (const char *str, va_list ap) NO_RETURN;

Gerd Moellmann's avatar
Gerd Moellmann committed
108

109 110 111 112 113 114
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
               (int) (FRAME_LINES (XFRAME (selected_frame))     \
                      - curY (tty)),                            \
               cmputc)

115 116
#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
117

118
#define OUTPUT_IF(tty, a)                                               \
119 120 121 122 123 124 125
  do {                                                                  \
    if (a)                                                              \
      emacs_tputs ((tty), a,                                            \
                   (int) (FRAME_LINES (XFRAME (selected_frame))         \
                          - curY (tty) ),                               \
                   cmputc);                                             \
  } while (0)
126

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

129 130 131 132
/* If true, use "vs", otherwise use "ve" to make the cursor visible.  */

static int visible_cursor;

133
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
134

135
extern Lisp_Object Qspace, QCalign_to, QCwidth;
Jim Blandy's avatar
Jim Blandy committed
136

137
/* Functions to call after suspending a tty. */
138
Lisp_Object Vsuspend_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
139

140
/* Functions to call after resuming a tty. */
141
Lisp_Object Vresume_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
142

143
/* Chain of all tty device parameters. */
144
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
145

146 147 148 149
/* Nonzero means no need to redraw the entire frame on resuming a
   suspended Emacs.  This is useful on terminals with multiple
   pages, where one page is used for Emacs and another for all
   else. */
Jim Blandy's avatar
Jim Blandy committed
150
int no_redraw_on_reenter;
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

/* 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,
  NC_BLINK	 = 1 << 3,
  NC_DIM	 = 1 << 4,
  NC_BOLD	 = 1 << 5,
  NC_INVIS	 = 1 << 6,
  NC_PROTECT	 = 1 << 7,
  NC_ALT_CHARSET = 1 << 8
};

Jim Blandy's avatar
Jim Blandy committed
168 169
/* internal state */

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

172
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
173

174
/* The largest frame height in any call to calculate_costs.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
175

176
int max_frame_lines;
177

178 179 180
/* Non-zero if we have dropped our controlling tty and therefore
   should not open a frame on stdout. */
static int no_controlling_tty;
Jim Blandy's avatar
Jim Blandy committed
181

182
/* Provided for lisp packages.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
183

184 185
static int system_uses_terminfo;

186
char *tparam (char *, char *, int, int, ...);
187

188
extern char *tgetstr (char *, char **);
Jim Blandy's avatar
Jim Blandy committed
189

190

191
#ifdef HAVE_GPM
192 193
#include <sys/fcntl.h>

194
static void term_clear_mouse_face (void);
195 196
static void term_mouse_highlight (struct frame *f, int x, int y);

197 198
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
199 200 201 202 203 204 205 206 207

/* These variables describe the range of text currently shown in its
   mouse-face, together with the window they apply to.  As long as
   the mouse stays within this range, we need not redraw anything on
   its account.  Rows and columns are glyph matrix positions in
   MOUSE_FACE_WINDOW.  */
static int mouse_face_beg_row, mouse_face_beg_col;
static int mouse_face_end_row, mouse_face_end_col;
static int mouse_face_past_end;
208
static Lisp_Object mouse_face_window;
209 210 211 212
static int mouse_face_face_id;

static int pos_x, pos_y;
static int last_mouse_x, last_mouse_y;
213
#endif /* HAVE_GPM */
214

215
/* Ring the bell on a tty. */
216

217
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
218
tty_ring_bell (struct frame *f)
219 220
{
  struct tty_display_info *tty = FRAME_TTY (f);
221

222 223 224 225 226 227
  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
228 229 230
    }
}

231 232
/* Set up termcap modes for Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
233
void
234
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
235
{
236
  struct tty_display_info *tty = terminal->display_info.tty;
237

238
  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
239
    {
240 241
      if (tty->TS_termcap_modes)
        OUTPUT (tty, tty->TS_termcap_modes);
242
      else
243 244 245 246
        {
          /* Output enough newlines to scroll all the old screen contents
             off the screen, so it won't be overwritten and lost.  */
          int i;
247
          current_tty = tty;
248
          for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
249
            cmputc ('\n');
250 251
        }

252
      OUTPUT_IF (tty, tty->TS_termcap_modes);
253
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
254 255
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
256
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
257 258 259
    }
}

260 261
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
262
void
263
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
264
{
265
  struct tty_display_info *tty = terminal->display_info.tty;
266 267

  if (tty->output)
Jim Blandy's avatar
Jim Blandy committed
268
    {
269 270
      tty_turn_off_highlight (tty);
      tty_turn_off_insert (tty);
271 272 273 274
      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);
275
      /* Output raw CR so kernel can track the cursor hpos.  */
276
      current_tty = tty;
277
      cmputc ('\r');
278
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
279 280 281
    }
}

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

284
static void
285
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
286
{
287
  struct tty_display_info *tty = FRAME_TTY (f);
288

289 290
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
291 292
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
293 294
}

295 296
/* The implementation of set_terminal_window for termcap frames. */

297
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
298
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
299
{
300 301 302 303
  struct tty_display_info *tty = FRAME_TTY (f);

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

307 308
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
309 310
{
  char *buf;
311
  struct tty_display_info *tty = FRAME_TTY (f);
312

313 314 315 316
  if (tty->TS_set_scroll_region)
    buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1);
  else if (tty->TS_set_scroll_region_1)
    buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
317 318 319
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
320
  else
321
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
322

323
  OUTPUT (tty, buf);
324
  xfree (buf);
325
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
326
}
327

Jim Blandy's avatar
Jim Blandy committed
328

329
static void
330
tty_turn_on_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
331
{
332 333 334
  if (!tty->insert_mode)
    OUTPUT (tty, tty->TS_insert_mode);
  tty->insert_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
335 336
}

Andreas Schwab's avatar
Andreas Schwab committed
337
void
338
tty_turn_off_insert (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
339
{
340 341 342
  if (tty->insert_mode)
    OUTPUT (tty, tty->TS_end_insert_mode);
  tty->insert_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
343 344
}

345
/* Handle highlighting.  */
Jim Blandy's avatar
Jim Blandy committed
346

Andreas Schwab's avatar
Andreas Schwab committed
347
void
348
tty_turn_off_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
349
{
350 351 352
  if (tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_end_standout_mode);
  tty->standout_mode = 0;
Jim Blandy's avatar
Jim Blandy committed
353 354
}

355
static void
356
tty_turn_on_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
357
{
358 359 360
  if (!tty->standout_mode)
    OUTPUT_IF (tty, tty->TS_standout_mode);
  tty->standout_mode = 1;
Jim Blandy's avatar
Jim Blandy committed
361 362
}

363
static void
364
tty_toggle_highlight (struct tty_display_info *tty)
365
{
366
  if (tty->standout_mode)
367
    tty_turn_off_highlight (tty);
368
  else
369
    tty_turn_on_highlight (tty);
370 371
}

Gerd Moellmann's avatar
Gerd Moellmann committed
372 373 374 375

/* Make cursor invisible.  */

static void
376
tty_hide_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
377
{
378
  if (tty->cursor_hidden == 0)
379
    {
380 381
      tty->cursor_hidden = 1;
      OUTPUT_IF (tty, tty->TS_cursor_invisible);
382
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
383 384 385 386 387 388
}


/* Ensure that cursor is visible.  */

static void
389
tty_show_cursor (struct tty_display_info *tty)
Gerd Moellmann's avatar
Gerd Moellmann committed
390
{
391
  if (tty->cursor_hidden)
392
    {
393 394
      tty->cursor_hidden = 0;
      OUTPUT_IF (tty, tty->TS_cursor_normal);
395
      if (visible_cursor)
396
        OUTPUT_IF (tty, tty->TS_cursor_visible);
397
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
398 399 400
}


Jim Blandy's avatar
Jim Blandy committed
401 402 403 404
/* 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.  */

405 406
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
407 408
{
  if (inverse_video)
409
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
410
  else
411
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
412 413 414 415
}

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

Andreas Schwab's avatar
Andreas Schwab committed
416
static void
417
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
418
{
419
  if (inverse_video)
420
    tty_turn_on_highlight (tty);
421
  else
422
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
423 424 425
}


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

429
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
430
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
431
{
432
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
433

434 435
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
436
  if (! tty->costs_set)
437 438
    return;

439 440
  if (curY (tty) == vpos
      && curX (tty) == hpos)
Jim Blandy's avatar
Jim Blandy committed
441
    return;
442
  if (!tty->TF_standout_motion)
443
    tty_background_highlight (tty);
444
  if (!tty->TF_insmode_motion)
445
    tty_turn_off_insert (tty);
446
  cmgoto (tty, vpos, hpos);
Jim Blandy's avatar
Jim Blandy committed
447 448 449 450
}

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

451
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
452
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
453
{
454 455
  struct tty_display_info *tty = FRAME_TTY (f);

456 457
  if (curY (tty) == row
      && curX (tty) == col)
Jim Blandy's avatar
Jim Blandy committed
458
    return;
459
  if (!tty->TF_standout_motion)
460
    tty_background_highlight (tty);
461
  if (!tty->TF_insmode_motion)
462
    tty_turn_off_insert (tty);
463
  cmgoto (tty, row, col);
Jim Blandy's avatar
Jim Blandy committed
464 465 466 467
}

/* Erase operations */

468 469
/* Clear from cursor to end of frame on a termcap device. */

470
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
471
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
472 473
{
  register int i;
474
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
475

476
  if (tty->TS_clr_to_bottom)
Jim Blandy's avatar
Jim Blandy committed
477
    {
478
      tty_background_highlight (tty);
479
      OUTPUT (tty, tty->TS_clr_to_bottom);
Jim Blandy's avatar
Jim Blandy committed
480 481 482
    }
  else
    {
483
      for (i = curY (tty); i < FRAME_LINES (f); i++)
Jim Blandy's avatar
Jim Blandy committed
484
	{
Karoly Lorentey's avatar
Karoly Lorentey committed
485 486
	  cursor_to (f, i, 0);
	  clear_end_of_line (f, FRAME_COLS (f));
Jim Blandy's avatar
Jim Blandy committed
487 488 489 490
	}
    }
}

491
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
492

493
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
494
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
495
{
496
  struct tty_display_info *tty = FRAME_TTY (f);
497

498
  if (tty->TS_clr_frame)
Jim Blandy's avatar
Jim Blandy committed
499
    {
500
      tty_background_highlight (tty);
501
      OUTPUT (tty, tty->TS_clr_frame);
502
      cmat (tty, 0, 0);
Jim Blandy's avatar
Jim Blandy committed
503 504 505
    }
  else
    {
Karoly Lorentey's avatar
Karoly Lorentey committed
506 507
      cursor_to (f, 0, 0);
      clear_to_end (f);
Jim Blandy's avatar
Jim Blandy committed
508 509 510
    }
}

511
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
512 513 514

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

515
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
516
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
517 518
{
  register int i;
519
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
520

521 522
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
523
  if (! tty->costs_set)
524 525
    return;

526
  if (curX (tty) >= first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
527
    return;
528
  tty_background_highlight (tty);
529
  if (tty->TS_clr_line)
Jim Blandy's avatar
Jim Blandy committed
530
    {
531
      OUTPUT1 (tty, tty->TS_clr_line);
Jim Blandy's avatar
Jim Blandy committed
532 533 534
    }
  else
    {			/* have to do it the hard way */
535
      tty_turn_off_insert (tty);
Jim Blandy's avatar
Jim Blandy committed
536

Gerd Moellmann's avatar
Gerd Moellmann committed
537
      /* Do not write in last row last col with Auto-wrap on. */
538
      if (AutoWrap (tty)
Karoly Lorentey's avatar
Karoly Lorentey committed
539 540
          && curY (tty) == FrameRows (tty) - 1
	  && first_unused_hpos == FrameCols (tty))
Jim Blandy's avatar
Jim Blandy committed
541 542
	first_unused_hpos--;

543
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
544
	{
545 546 547
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
548
	}
549
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
550 551 552
    }
}

553 554 555 556 557 558 559 560 561 562 563 564
/* 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.  */
static int encode_terminal_src_size;
static int encode_terminal_dst_size;

/* 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.  */

unsigned char *
565
encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
Karl Heuer's avatar
Karl Heuer committed
566
{
567
  struct glyph *src_end = src + src_len;
568 569
  unsigned char *buf;
  int nchars, nbytes, required;
Karl Heuer's avatar
Karl Heuer committed
570 571
  register int tlen = GLYPH_TABLE_LENGTH;
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
572
  Lisp_Object charset_list;
573

574 575
  /* 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
576 577
     Vglyph_table contains a string or a composite glyph is
     encountered.  */
578 579 580
  required = MAX_MULTIBYTE_LENGTH * src_len;
  if (encode_terminal_src_size < required)
    {
581
      if (encode_terminal_src)
582
	encode_terminal_src = xrealloc (encode_terminal_src, required);
583 584
      else
	encode_terminal_src = xmalloc (required);
585 586
      encode_terminal_src_size = required;
    }
587

588
  charset_list = coding_charset_list (coding);
Karl Heuer's avatar
Karl Heuer committed
589

590 591 592
  buf = encode_terminal_src;
  nchars = 0;
  while (src < src_end)
Karl Heuer's avatar
Karl Heuer committed
593
    {
Kenichi Handa's avatar
Kenichi Handa committed
594 595
      if (src->type == COMPOSITE_GLYPH)
	{
596 597
	  struct composition *cmp;
	  Lisp_Object gstring;
Kenichi Handa's avatar
Kenichi Handa committed
598 599 600
	  int i;

	  nbytes = buf - encode_terminal_src;
601 602 603
	  if (src->u.cmp.automatic)
	    {
	      gstring = composition_gstring_from_id (src->u.cmp.id);
604
	      required = src->u.cmp.to + 1 - src->u.cmp.from;
605 606 607 608 609 610
	    }
	  else
	    {
	      cmp = composition_table[src->u.cmp.id];
	      required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
	    }
Kenichi Handa's avatar
Kenichi Handa committed
611 612 613 614 615 616 617 618 619

	  if (encode_terminal_src_size < nbytes + required)
	    {
	      encode_terminal_src_size = nbytes + required;
	      encode_terminal_src = xrealloc (encode_terminal_src,
					      encode_terminal_src_size);
	      buf = encode_terminal_src + nbytes;
	    }

620
	  if (src->u.cmp.automatic)
621
	    for (i = src->u.cmp.from; i <= src->u.cmp.to; i++)
622 623 624 625 626
	      {
		Lisp_Object g = LGSTRING_GLYPH (gstring, i);
		int c = LGLYPH_CHAR (g);

		if (! char_charset (c, charset_list, NULL))
627
		  c = '?';
628 629 630 631 632 633 634 635
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
	  else
	    for (i = 0; i < cmp->glyph_len; i++)
	      {
		int c = COMPOSITION_GLYPH (cmp, i);

636 637 638 639 640 641 642 643 644 645 646 647 648 649
		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 = '?';
650 651 652
		buf += CHAR_STRING (c, buf);
		nchars++;
	      }
Kenichi Handa's avatar
Kenichi Handa committed
653
	}
Karl Heuer's avatar
Karl Heuer committed
654
      /* We must skip glyphs to be padded for a wide character.  */
Kenichi Handa's avatar
Kenichi Handa committed
655
      else if (! CHAR_GLYPH_PADDING_P (*src))
Karl Heuer's avatar
Karl Heuer committed
656
	{
657
	  GLYPH g;
658 659 660
	  int c;
	  Lisp_Object string;

661
	  string = Qnil;
662
	  SET_GLYPH_FROM_CHAR_GLYPH (g, src[0]);
663

664
	  if (GLYPH_INVALID_P (g) || GLYPH_SIMPLE_P (tbase, tlen, g))
665
	    {
666
	      /* This glyph doesn't have an entry in Vglyph_table.  */
667 668
	      c = src->u.ch;
	    }
669
	  else
Karl Heuer's avatar
Karl Heuer committed
670
	    {
671
	      /* This glyph has an entry in Vglyph_table,
Karl Heuer's avatar
Karl Heuer committed
672 673
		 so process any alias before testing for simpleness.  */
	      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
674 675

	      if (GLYPH_SIMPLE_P (tbase, tlen, g))
676 677
		/* We set the multi-byte form of a character in G
		   (that should be an ASCII character) at WORKBUF.  */
678
		c = GLYPH_CHAR (g);
679
	      else
680
		/* We have a string in Vglyph_table.  */
681
		string = tbase[GLYPH_CHAR (g)];
Richard M. Stallman's avatar
Richard M. Stallman committed
682
	    }
683

684
	  if (NILP (string))
685
	    {
Kenichi Handa's avatar
Kenichi Handa committed
686 687 688 689 690 691 692 693
	      nbytes = buf - encode_terminal_src;
	      if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
		{
		  encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
		}
694
	      if (char_charset (c, charset_list, NULL))
695
		{
696 697 698
		  /* Store the multibyte form of C at BUF.  */
		  buf += CHAR_STRING (c, buf);
		  nchars++;
699 700 701
		}
	      else
		{
702 703
		  /* C is not encodable.  */
		  *buf++ = '?';
704
		  nchars++;
705 706 707 708 709 710
		  while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
		    {
		      *buf++ = '?';
		      nchars++;
		      src++;
		    }
711
		}
712 713 714
	    }
	  else
	    {
715 716 717 718 719
	      unsigned char *p = SDATA (string), *pend = p + SBYTES (string);

	      if (! STRING_MULTIBYTE (string))
		string = string_to_multibyte (string);
	      nbytes = buf - encode_terminal_src;
720
	      if (encode_terminal_src_size < nbytes + SBYTES (string))
721
		{
722 723 724 725
		  encode_terminal_src_size = nbytes + SBYTES (string);
		  encode_terminal_src = xrealloc (encode_terminal_src,
						  encode_terminal_src_size);
		  buf = encode_terminal_src + nbytes;
726
		}
727
	      memcpy (buf, SDATA (string), SBYTES (string));
728 729
	      buf += SBYTES (string);
	      nchars += SCHARS (string);
730
	    }
Karl Heuer's avatar
Karl Heuer committed
731
	}
732 733 734 735 736 737 738
      src++;
    }

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

741 742 743
  nbytes = buf - encode_terminal_src;
  coding->source = encode_terminal_src;
  if (encode_terminal_dst_size == 0)
744
    {
745
      encode_terminal_dst_size = encode_terminal_src_size;
746 747 748 749 750
      if (encode_terminal_dst)
	encode_terminal_dst = xrealloc (encode_terminal_dst,
					encode_terminal_dst_size);
      else
	encode_terminal_dst = xmalloc (encode_terminal_dst_size);
751
    }
752 753 754
  coding->destination = encode_terminal_dst;
  coding->dst_bytes = encode_terminal_dst_size;
  encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
755
  /* coding->destination may have been reallocated.  */
756 757
  encode_terminal_dst = coding->destination;
  encode_terminal_dst_size = coding->dst_bytes;
758

759
  return (encode_terminal_dst);
Karl Heuer's avatar
Karl Heuer committed
760 761
}

Jim Blandy's avatar
Jim Blandy committed
762

Miles Bader's avatar
Miles Bader committed
763

764 765
/* An implementation of write_glyphs for termcap frames. */

766
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
767
tty_write_glyphs (struct frame *f, struct glyph *string, int len)
Jim Blandy's avatar
Jim Blandy committed
768
{
769 770
  unsigned char *conversion_buffer;
  struct coding_system *coding;
Jim Blandy's avatar
Jim Blandy committed
771

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

774
  tty_turn_off_insert (tty);
775
  tty_hide_cursor (tty);
Jim Blandy's avatar
Jim Blandy committed
776

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

780 781 782
  if (AutoWrap (tty)
      && curY (tty) + 1 == FRAME_LINES (f)
      && (curX (tty) + len) == FRAME_COLS (f))
Jim Blandy's avatar
Jim Blandy committed
783
    len --;
Karl Heuer's avatar
Karl Heuer committed
784 785
  if (len <= 0)
    return;
Jim Blandy's avatar
Jim Blandy committed
786

787
  cmplus (tty, len);
788

789 790 791
  /* If terminal_coding does any conversion, use it, otherwise use
     safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
     because it always return 1 if the member src_multibyte is 1.  */
792 793
  coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK
	    ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding);
794 795
  /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
     the tail.  */
796
  coding->mode &= ~CODING_MODE_LAST_BLOCK;
797

Karl Heuer's avatar
Karl Heuer committed
798
  while (len > 0)
Jim Blandy's avatar
Jim Blandy committed
799
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
800
      /* Identify a run of glyphs with the same face.  */
801
      int face_id = string->face_id;
Gerd Moellmann's avatar
Gerd Moellmann committed
802
      int n;
803

Gerd Moellmann's avatar
Gerd Moellmann committed
804
      for (n = 1; n < len; ++n)
805
	if (string[n].face_id != face_id)
Gerd Moellmann's avatar
Gerd Moellmann committed
806 807 808
	  break;

      /* Turn appearance modes of the face of the run on.  */
809
      tty_highlight_if_desired (tty);
Gerd Moellmann's avatar
Gerd Moellmann committed
810 811
      turn_on_face (f, face_id);

812 813 814 815 816
      if (n == len)
	/* This is the last run.  */
	coding->mode |= CODING_MODE_LAST_BLOCK;
      conversion_buffer = encode_terminal_code (string, n, coding);
      if (coding->produced > 0)