term.c 113 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 P_ ((const char *, int, int (*)(int)));
extern int tgetent P_ ((char *, const char *));
extern int tgetflag P_ ((char *id));
extern int tgetnum P_ ((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
static void tty_set_scroll_region P_ ((struct frame *f, int start, int stop));
Gerd Moellmann's avatar
Gerd Moellmann committed
95 96
static void turn_on_face P_ ((struct frame *, int face_id));
static void turn_off_face P_ ((struct frame *, int face_id));
97 98
static void tty_show_cursor P_ ((struct tty_display_info *));
static void tty_hide_cursor P_ ((struct tty_display_info *));
99
static void tty_background_highlight P_ ((struct tty_display_info *tty));
100 101
static void clear_tty_hooks P_ ((struct terminal *terminal));
static void set_tty_hooks P_ ((struct terminal *terminal));
102
static void dissociate_if_controlling_tty P_ ((int fd));
103
static void delete_tty P_ ((struct terminal *));
Gerd Moellmann's avatar
Gerd Moellmann committed
104

105 106 107 108 109 110
#define OUTPUT(tty, a)                                          \
  emacs_tputs ((tty), a,                                        \
               (int) (FRAME_LINES (XFRAME (selected_frame))     \
                      - curY (tty)),                            \
               cmputc)

111 112
#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
113

114
#define OUTPUT_IF(tty, a)                                               \
115 116 117 118 119 120 121
  do {                                                                  \
    if (a)                                                              \
      emacs_tputs ((tty), a,                                            \
                   (int) (FRAME_LINES (XFRAME (selected_frame))         \
                          - curY (tty) ),                               \
                   cmputc);                                             \
  } while (0)
122

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

125 126 127 128
/* If true, use "vs", otherwise use "ve" to make the cursor visible.  */

static int visible_cursor;

129
/* Display space properties */
Jim Blandy's avatar
Jim Blandy committed
130

131
extern Lisp_Object Qspace, QCalign_to, QCwidth;
Jim Blandy's avatar
Jim Blandy committed
132

133
/* Functions to call after suspending a tty. */
134
Lisp_Object Vsuspend_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
135

136
/* Functions to call after resuming a tty. */
137
Lisp_Object Vresume_tty_functions;
Jim Blandy's avatar
Jim Blandy committed
138

139
/* Chain of all tty device parameters. */
140
struct tty_display_info *tty_list;
Jim Blandy's avatar
Jim Blandy committed
141

142 143 144 145
/* 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
146
int no_redraw_on_reenter;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

/* 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
164 165
/* internal state */

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

168
int max_frame_cols;
Gerd Moellmann's avatar
Gerd Moellmann committed
169

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

172
int max_frame_lines;
173

174 175 176
/* 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
177

178
/* Provided for lisp packages.  */
Gerd Moellmann's avatar
Gerd Moellmann committed
179

180 181
static int system_uses_terminfo;

Jim Blandy's avatar
Jim Blandy committed
182
char *tparam ();
183 184

extern char *tgetstr ();
Jim Blandy's avatar
Jim Blandy committed
185

186

187
#ifdef HAVE_GPM
188 189
#include <sys/fcntl.h>

190 191 192
static void term_clear_mouse_face ();
static void term_mouse_highlight (struct frame *f, int x, int y);

193 194
/* The device for which we have enabled gpm support (or NULL).  */
struct tty_display_info *gpm_tty = NULL;
195 196 197 198 199 200 201 202 203

/* 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;
204
static Lisp_Object mouse_face_window;
205 206 207 208
static int mouse_face_face_id;

static int pos_x, pos_y;
static int last_mouse_x, last_mouse_y;
209
#endif /* HAVE_GPM */
210

211
/* Ring the bell on a tty. */
212

213
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
214
tty_ring_bell (struct frame *f)
215 216
{
  struct tty_display_info *tty = FRAME_TTY (f);
217

218 219 220 221 222 223
  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
224 225 226
    }
}

227 228
/* Set up termcap modes for Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
229
void
230
tty_set_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
231
{
232
  struct tty_display_info *tty = terminal->display_info.tty;
233

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

248
      OUTPUT_IF (tty, tty->TS_termcap_modes);
249
      OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
250 251
      OUTPUT_IF (tty, tty->TS_keypad_mode);
      losecursor (tty);
252
      fflush (tty->output);
Jim Blandy's avatar
Jim Blandy committed
253 254 255
    }
}

256 257
/* Reset termcap modes before exiting Emacs. */

Andreas Schwab's avatar
Andreas Schwab committed
258
void
259
tty_reset_terminal_modes (struct terminal *terminal)
Jim Blandy's avatar
Jim Blandy committed
260
{
261
  struct tty_display_info *tty = terminal->display_info.tty;
262 263

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

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

280
static void
281
tty_update_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
282
{
283
  struct tty_display_info *tty = FRAME_TTY (f);
284

285 286
  if (!XWINDOW (selected_window)->cursor_off_p)
    tty_show_cursor (tty);
287 288
  tty_turn_off_insert (tty);
  tty_background_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
289 290
}

291 292
/* The implementation of set_terminal_window for termcap frames. */

293
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
294
tty_set_terminal_window (struct frame *f, int size)
Jim Blandy's avatar
Jim Blandy committed
295
{
296 297 298 299
  struct tty_display_info *tty = FRAME_TTY (f);

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

303 304
static void
tty_set_scroll_region (struct frame *f, int start, int stop)
Jim Blandy's avatar
Jim Blandy committed
305 306
{
  char *buf;
307
  struct tty_display_info *tty = FRAME_TTY (f);
308

309 310 311 312
  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,
313 314 315
		  FRAME_LINES (f), start,
		  FRAME_LINES (f) - stop,
		  FRAME_LINES (f));
Jim Blandy's avatar
Jim Blandy committed
316
  else
317
    buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
318

319
  OUTPUT (tty, buf);
320
  xfree (buf);
321
  losecursor (tty);
Jim Blandy's avatar
Jim Blandy committed
322
}
323

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

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

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

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

359
static void
360
tty_toggle_highlight (struct tty_display_info *tty)
361
{
362
  if (tty->standout_mode)
363
    tty_turn_off_highlight (tty);
364
  else
365
    tty_turn_on_highlight (tty);
366 367
}

Gerd Moellmann's avatar
Gerd Moellmann committed
368 369 370 371

/* Make cursor invisible.  */

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


/* Ensure that cursor is visible.  */

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


Jim Blandy's avatar
Jim Blandy committed
397 398 399 400
/* 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.  */

401 402
static void
tty_background_highlight (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
403 404
{
  if (inverse_video)
405
    tty_turn_on_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
406
  else
407
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
408 409 410 411
}

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

Andreas Schwab's avatar
Andreas Schwab committed
412
static void
413
tty_highlight_if_desired (struct tty_display_info *tty)
Jim Blandy's avatar
Jim Blandy committed
414
{
415
  if (inverse_video)
416
    tty_turn_on_highlight (tty);
417
  else
418
    tty_turn_off_highlight (tty);
Jim Blandy's avatar
Jim Blandy committed
419 420 421
}


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

425
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
426
tty_cursor_to (struct frame *f, int vpos, int hpos)
Jim Blandy's avatar
Jim Blandy committed
427
{
428
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
429

430 431
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
432
  if (! tty->costs_set)
433 434
    return;

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

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

447
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
448
tty_raw_cursor_to (struct frame *f, int row, int col)
Jim Blandy's avatar
Jim Blandy committed
449
{
450 451
  struct tty_display_info *tty = FRAME_TTY (f);

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

464 465
/* Clear from cursor to end of frame on a termcap device. */

466
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
467
tty_clear_to_end (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
468 469
{
  register int i;
470
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
471

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

487
/* Clear an entire termcap frame. */
Jim Blandy's avatar
Jim Blandy committed
488

489
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
490
tty_clear_frame (struct frame *f)
Jim Blandy's avatar
Jim Blandy committed
491
{
492
  struct tty_display_info *tty = FRAME_TTY (f);
493

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

507
/* An implementation of clear_end_of_line for termcap frames.
Jim Blandy's avatar
Jim Blandy committed
508 509 510

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

511
static void
Karoly Lorentey's avatar
Karoly Lorentey committed
512
tty_clear_end_of_line (struct frame *f, int first_unused_hpos)
Jim Blandy's avatar
Jim Blandy committed
513 514
{
  register int i;
515
  struct tty_display_info *tty = FRAME_TTY (f);
Jim Blandy's avatar
Jim Blandy committed
516

517 518
  /* Detect the case where we are called from reset_sys_modes
     and the costs have never been calculated.  Do nothing.  */
519
  if (! tty->costs_set)
520 521
    return;

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

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

539
      for (i = curX (tty); i < first_unused_hpos; i++)
Jim Blandy's avatar
Jim Blandy committed
540
	{
541 542 543
	  if (tty->termscript)
	    fputc (' ', tty->termscript);
	  fputc (' ', tty->output);
Jim Blandy's avatar
Jim Blandy committed
544
	}
545
      cmplus (tty, first_unused_hpos - curX (tty));
Jim Blandy's avatar
Jim Blandy committed
546 547 548
    }
}

549 550 551 552 553 554 555 556 557 558 559 560 561
/* 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 *
encode_terminal_code (src, src_len, coding)
Gerd Moellmann's avatar
Gerd Moellmann committed
562
     struct glyph *src;
Karl Heuer's avatar
Karl Heuer committed
563
     int src_len;
564
     struct coding_system *coding;
Karl Heuer's avatar
Karl Heuer committed
565
{
566
  struct glyph *src_end = src + src_len;
567 568
  unsigned char *buf;
  int nchars, nbytes, required;
Karl Heuer's avatar
Karl Heuer committed
569 570
  register int tlen = GLYPH_TABLE_LENGTH;
  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
571
  Lisp_Object charset_list;
572

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

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

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

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

	  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;
	    }

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

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

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

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

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

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

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

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

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

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

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

Jim Blandy's avatar
Jim Blandy committed
761

Miles Bader's avatar
Miles Bader committed
762

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

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

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

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

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

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

786
  cmplus (tty, len);
787