aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaroly Lorentey2004-02-28 01:23:39 +0000
committerKaroly Lorentey2004-02-28 01:23:39 +0000
commit0b0d3e0bcefdde298893aaad2e816e1503cef222 (patch)
tree439342044857514ad784de0470f5546eb9c3ef9a
parent2fc0cf2aefa777e5fe48596e2d43774b28051931 (diff)
downloademacs-0b0d3e0bcefdde298893aaad2e816e1503cef222.tar.gz
emacs-0b0d3e0bcefdde298893aaad2e816e1503cef222.zip
Implemented suspending of emacsclient frames.
lib-src/emacsclient.c (quote_file_name): Renamed to quote_argument. (unquote_argument, handle_sigcont, handle_sigtstp): New functions. (out, in): New global variables for communicating with the Emacs process. (init_signals): Set up handlers for SIGCONT, SIGTSTP and SIGTTOU. (main): Changed out and in to global variables. Prepend `-eval' or '-file' to each argument. Use fsync to force sending the strings to Emacs. Removed obsolete -bad-version code. Support the -suspend command. Cleaned up newline handling. lisp/frame.el (suspend-frame): New function. Substitute key definition of suspend-emacs with suspend-frame. lisp/server.el (server-log): Cosmetic change in log format. (server-handle-delete-tty, server-handle-delete-frame): Added logging. (server-handle-suspend-tty, server-quote-arg): New functions. (server-start): Install server-handle-suspend-tty. (server-process-filter): Reorganized source code for clarity. Implemented -resume, -suspend and -ignore commands. lisp/term/x-win.el (x-initialize-window-system): Don't change the binding of C-z. src/cm.c: Replaced TTY_INPUT, TTY_OUTPUT, TTY_TERMSCRIPT calls with their macro expansion. src/dispnew.c: Ditto. src/frame.c: Ditto. src/keyboard.c: Ditto. src/sysdep.c: Ditto. src/keyboard.c (tty_read_avail_input): Don't read if the terminal is suspended. src/sysdep.c (discard_tty_input, init_sys_modes, reset_sys_modes): Ditto. src/term.c (tty_set_terminal_modes, tty_reset_terminal_modes): Ditto. src/term.c (Vsuspend_tty_functions, Vresume_tty_functions): New hooks. (syms_of_term): Defvar them. (term_init): Don't allow opening a new frame on a suspended tty device. (Fsuspend_tty, Fresume_tty): New functions. (syms_of_term): Defsubr them. src/termchar.c (struct tty_display_info): Update documentation of input and output. (TTY_INPUT, TTY_OUTPUT, TTY_TERMSCRIPT): Removed. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-105
-rw-r--r--README.multi-tty57
-rw-r--r--lib-src/emacsclient.c244
-rw-r--r--lisp/frame.el18
-rw-r--r--lisp/server.el296
-rw-r--r--lisp/term/x-win.el6
-rw-r--r--src/cm.c18
-rw-r--r--src/dispnew.c58
-rw-r--r--src/frame.c5
-rw-r--r--src/keyboard.c15
-rw-r--r--src/sysdep.c96
-rw-r--r--src/term.c234
-rw-r--r--src/termchar.h10
-rw-r--r--src/termhooks.h1
13 files changed, 741 insertions, 317 deletions
diff --git a/README.multi-tty b/README.multi-tty
index 68cae7a2060..43dfdcbc91f 100644
--- a/README.multi-tty
+++ b/README.multi-tty
@@ -200,22 +200,50 @@ THINGS TO DO
200 argument-handling is done in Lisp, so this should be quite easy to 200 argument-handling is done in Lisp, so this should be quite easy to
201 implement. 201 implement.
202 202
203** Very strange bug: visible-bell does not work on secondary 203** Make `struct display' accessible to Lisp programs. Accessor functions:
204 terminals. This might be something xterm (konsole) specific.
205 204
206** Find out the best way to support suspending Emacs with multiple 205 (displayp OBJECT): Returns t if OBJECT is a display.
207 ttys. My guess: disable it on the controlling tty, but from other
208 ttys pass it on to emacsclient somehow. (It is (I hope) trivial to
209 extend emacsclient to handle suspend/resume. A `kill -STOP' almost
210 works right now.)
211 206
212** Clean up the frame-local variable system. I think it's ugly and 207 (selected-display): Returns the display object of the selected frame.
213 error-prone. But maybe I just haven't yet fully understood it. 208
209 (frame-display FRAME): Returns the display object of FRAME.
210
211 (display-frames DISPLAY): Returns a list of frames on DISPLAY.
212
213 (display-type DISPLAY): Returns the type of DISPLAY, as a
214 symbol. (See `framep'.)
215
216 (display-device DISPLAY): Returns the name of the device that
217 DISPLAY uses, as a string. (E.g: "/dev/pts/16", or
218 ":0.0")
219
220 See next issue why this is necessary.
221
222** The following needs to be supported:
223
224 $ emacsclient -t
225 C-z
226 $ bg
227 $ emacsclient -t
228 (This fails now.)
229
230 The cleanest way to solve this is to allow multiple displays on the
231 same terminal device; each new emacsclient process should create
232 its own display. As displays are currently identified by their
233 device names, this is not possible until struct display becomes
234 accessible as a Lisp-level object.
214 235
215** Add an elaborate mechanism for display-local variables. (There are 236** Add an elaborate mechanism for display-local variables. (There are
216 already a few of these; search for `terminal-local' in the Elisp 237 already a few of these; search for `terminal-local' in the Elisp
217 manual.) 238 manual.)
218 239
240** Very strange bug: visible-bell does not work on secondary
241 terminals in xterm and konsole. The screen does flicker a bit,
242 but it's so quick it isn't noticable.
243
244** Clean up the frame-local variable system. I think it's ugly and
245 error-prone. But maybe I just haven't yet fully understood it.
246
219** Move baud_rate to struct display. 247** Move baud_rate to struct display.
220 248
221** Implement support for starting an interactive Emacs session without 249** Implement support for starting an interactive Emacs session without
@@ -667,4 +695,15 @@ DIARY OF CHANGES
667 complaints seem to be caused by bugs in term.el; they are not 695 complaints seem to be caused by bugs in term.el; they are not
668 related to multi-tty.) 696 related to multi-tty.)
669 697
698-- Find out the best way to support suspending Emacs with multiple
699 ttys. My guess: disable it on the controlling tty, but from other
700 ttys pass it on to emacsclient somehow. (It is (I hope) trivial to
701 extend emacsclient to handle suspend/resume. A `kill -STOP' almost
702 works right now.)
703
704 (Done. I needed to play with signal handling and the server
705 protocol a bit to make emacsclient behave as a normal UNIX program
706 wrt foreground/background process groups.)
707
708
670;;; arch-tag: 8da1619e-2e79-41a8-9ac9-a0485daad17d 709;;; arch-tag: 8da1619e-2e79-41a8-9ac9-a0485daad17d
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index c1c8ee8f160..79642cbe47e 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -114,7 +114,7 @@ decode_options (argc, argv)
114 display = getenv ("DISPLAY"); 114 display = getenv ("DISPLAY");
115 if (display && strlen (display) == 0) 115 if (display && strlen (display) == 0)
116 display = NULL; 116 display = NULL;
117 117
118 if (display) 118 if (display)
119 window_system = 1; 119 window_system = 1;
120 else 120 else
@@ -169,7 +169,7 @@ decode_options (argc, argv)
169 window_system = 0; 169 window_system = 0;
170 tty = 0; 170 tty = 0;
171 break; 171 break;
172 172
173 case 'H': 173 case 'H':
174 print_help_and_exit (); 174 print_help_and_exit ();
175 break; 175 break;
@@ -212,19 +212,21 @@ Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
212 exit (0); 212 exit (0);
213} 213}
214 214
215/* In NAME, insert a & before each &, each space, each newline, and 215/* In STR, insert a & before each &, each space, each newline, and
216 any initial -. Change spaces to underscores, too, so that the 216 any initial -. Change spaces to underscores, too, so that the
217 return value never contains a space. */ 217 return value never contains a space.
218
219 Does not change the string. Outputs the result to STREAM. */
218 220
219void 221void
220quote_file_name (name, stream) 222quote_argument (str, stream)
221 char *name; 223 char *str;
222 FILE *stream; 224 FILE *stream;
223{ 225{
224 char *copy = (char *) malloc (strlen (name) * 2 + 1); 226 char *copy = (char *) malloc (strlen (str) * 2 + 1);
225 char *p, *q; 227 char *p, *q;
226 228
227 p = name; 229 p = str;
228 q = copy; 230 q = copy;
229 while (*p) 231 while (*p)
230 { 232 {
@@ -242,7 +244,7 @@ quote_file_name (name, stream)
242 } 244 }
243 else 245 else
244 { 246 {
245 if (*p == '&' || (*p == '-' && p == name)) 247 if (*p == '&' || (*p == '-' && p == str))
246 *q++ = '&'; 248 *q++ = '&';
247 *q++ = *p++; 249 *q++ = *p++;
248 } 250 }
@@ -254,6 +256,41 @@ quote_file_name (name, stream)
254 free (copy); 256 free (copy);
255} 257}
256 258
259
260/* The inverse of quote_argument. Removes quoting in string STR by
261 modifying the string in place. Returns STR. */
262
263char *
264unquote_argument (str)
265 char *str;
266{
267 char *p, *q;
268
269 if (! str)
270 return str;
271
272 p = str;
273 q = str;
274 while (*p)
275 {
276 if (*p == '&')
277 {
278 p++;
279 if (*p == '&')
280 *p = '&';
281 else if (*p == '_')
282 *p = ' ';
283 else if (*p == 'n')
284 *p = '\n';
285 else if (*p == '-')
286 *p = '-';
287 }
288 *q++ = *p++;
289 }
290 *q = 0;
291 return str;
292}
293
257/* Like malloc but get fatal error if memory is exhausted. */ 294/* Like malloc but get fatal error if memory is exhausted. */
258 295
259long * 296long *
@@ -288,8 +325,12 @@ fail (void)
288 } 325 }
289} 326}
290 327
328/* The process id of Emacs. */
291int emacs_pid; 329int emacs_pid;
292 330
331/* File handles for communicating with Emacs. */
332FILE *out, *in;
333
293/* A signal handler that passes the signal to the Emacs process. 334/* A signal handler that passes the signal to the Emacs process.
294 Useful for SIGWINCH. */ 335 Useful for SIGWINCH. */
295 336
@@ -305,8 +346,62 @@ pass_signal_to_emacs (int signalnum)
305 errno = old_errno; 346 errno = old_errno;
306} 347}
307 348
349/* Signal handler for SIGCONT; notify the Emacs process that it can
350 now resume our tty frame. */
351
352SIGTYPE
353handle_sigcont (int signalnum)
354{
355 int old_errno = errno;
356
357 if (tcgetpgrp (1) == getpgrp ())
358 {
359 /* We are in the foreground. */
360 fprintf (out, "-resume \n");
361 fflush (out);
362 fsync (fileno (out));
363 }
364 else
365 {
366 /* We are in the background; cancel the continue. */
367 kill (getpid (), SIGSTOP);
368 }
369 errno = old_errno;
370}
371
372/* Signal handler for SIGTSTP; notify the Emacs process that we are
373 going to sleep. Normally the suspend is initiated by Emacs via
374 server-handle-suspend-tty, but if the server gets out of sync with
375 reality, we may get a SIGTSTP on C-z. Handling this signal and
376 notifying Emacs about it should get things under control again. */
377
378SIGTYPE
379handle_sigtstp (int signalnum)
380{
381 int old_errno = errno;
382 sigset_t set;
383
384 if (out)
385 {
386 fprintf (out, "-suspend \n");
387 fflush (out);
388 fsync (fileno (out));
389 }
390
391 /* Unblock this signal and call the default handler by temprarily
392 changing the handler and resignalling. */
393 sigprocmask (SIG_BLOCK, NULL, &set);
394 sigdelset (&set, signalnum);
395 signal (signalnum, SIG_DFL);
396 kill (getpid (), signalnum);
397 sigprocmask (SIG_SETMASK, &set, NULL); /* Let's the above signal through. */
398 signal (signalnum, handle_sigtstp);
399
400 errno = old_errno;
401}
402
308/* Set up signal handlers before opening a frame on the current tty. */ 403/* Set up signal handlers before opening a frame on the current tty. */
309 404
310void 405void
311init_signals (void) 406init_signals (void)
312{ 407{
@@ -320,6 +415,10 @@ init_signals (void)
320 signal (SIGINT, pass_signal_to_emacs); 415 signal (SIGINT, pass_signal_to_emacs);
321 signal (SIGQUIT, pass_signal_to_emacs); 416 signal (SIGQUIT, pass_signal_to_emacs);
322#endif 417#endif
418
419 signal (SIGCONT, handle_sigcont);
420 signal (SIGTSTP, handle_sigtstp);
421 signal (SIGTTOU, handle_sigtstp);
323} 422}
324 423
325 424
@@ -378,7 +477,7 @@ strprefix (char *prefix, char *string)
378 477
379 if (!string) 478 if (!string)
380 return 0; 479 return 0;
381 480
382 for (i = 0; prefix[i]; i++) 481 for (i = 0; prefix[i]; i++)
383 if (!string[i] || string[i] != prefix[i]) 482 if (!string[i] || string[i] != prefix[i])
384 return 0; 483 return 0;
@@ -391,7 +490,6 @@ main (argc, argv)
391 char **argv; 490 char **argv;
392{ 491{
393 int s, i, needlf = 0; 492 int s, i, needlf = 0;
394 FILE *out, *in;
395 struct sockaddr_un server; 493 struct sockaddr_un server;
396 char *cwd, *str; 494 char *cwd, *str;
397 char string[BUFSIZ]; 495 char string[BUFSIZ];
@@ -427,9 +525,9 @@ main (argc, argv)
427 int sock_status = 0; 525 int sock_status = 0;
428 int default_sock = !socket_name; 526 int default_sock = !socket_name;
429 int saved_errno = 0; 527 int saved_errno = 0;
430 528
431 char *server_name = "server"; 529 char *server_name = "server";
432 530
433 if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\')) 531 if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
434 { /* socket_name is a file name component. */ 532 { /* socket_name is a file name component. */
435 server_name = socket_name; 533 server_name = socket_name;
@@ -571,17 +669,14 @@ To start the server in Emacs, type \"M-x server-start\".\n",
571 669
572 /* First of all, send our version number for verification. */ 670 /* First of all, send our version number for verification. */
573 fprintf (out, "-version %s ", VERSION); 671 fprintf (out, "-version %s ", VERSION);
574 672
575 if (nowait) 673 if (nowait)
576 fprintf (out, "-nowait "); 674 fprintf (out, "-nowait ");
577 675
578 if (eval)
579 fprintf (out, "-eval ");
580
581 if (display) 676 if (display)
582 { 677 {
583 fprintf (out, "-display "); 678 fprintf (out, "-display ");
584 quote_file_name (display, out); 679 quote_argument (display, out);
585 fprintf (out, " "); 680 fprintf (out, " ");
586 } 681 }
587 682
@@ -589,7 +684,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
589 { 684 {
590 char *tty_name = ttyname (fileno (stdin)); 685 char *tty_name = ttyname (fileno (stdin));
591 char *type = getenv ("TERM"); 686 char *type = getenv ("TERM");
592 687
593 if (! tty_name) 688 if (! tty_name)
594 { 689 {
595 fprintf (stderr, "%s: could not get terminal name\n", progname); 690 fprintf (stderr, "%s: could not get terminal name\n", progname);
@@ -610,44 +705,60 @@ To start the server in Emacs, type \"M-x server-start\".\n",
610 " is not supported\n", progname); 705 " is not supported\n", progname);
611 fail (); 706 fail ();
612 } 707 }
613 708
614 init_signals (); 709 init_signals ();
615 710
616 fprintf (out, "-tty "); 711 fprintf (out, "-tty ");
617 quote_file_name (tty_name, out); 712 quote_argument (tty_name, out);
618 fprintf (out, " "); 713 fprintf (out, " ");
619 quote_file_name (type, out); 714 quote_argument (type, out);
620 fprintf (out, " "); 715 fprintf (out, " ");
621 } 716 }
622 717
623 if (window_system) 718 if (window_system)
624 fprintf (out, "-window-system "); 719 fprintf (out, "-window-system ");
625 720
626 if ((argc - optind > 0)) 721 if ((argc - optind > 0))
627 { 722 {
628 for (i = optind; i < argc; i++) 723 for (i = optind; i < argc; i++)
629 { 724 {
725 int relative = 0;
726
630 if (eval) 727 if (eval)
631 ; /* Don't prepend any cwd or anything like that. */ 728 {
632 else if (*argv[i] == '+') 729 /* Don't prepend any cwd or anything like that. */
633 { 730 fprintf (out, "-eval ");
731 quote_argument (argv[i], out);
732 fprintf (out, " ");
733 continue;
734 }
735
736 if (*argv[i] == '+')
737 {
634 char *p = argv[i] + 1; 738 char *p = argv[i] + 1;
635 while (isdigit ((unsigned char) *p) || *p == ':') p++; 739 while (isdigit ((unsigned char) *p) || *p == ':') p++;
636 if (*p != 0) 740 if (*p == 0)
637 { 741 {
638 quote_file_name (cwd, out); 742 fprintf (out, "-position ");
639 fprintf (out, "/"); 743 quote_argument (argv[i], out);
640 } 744 fprintf (out, " ");
641 } 745 continue;
642 else if (*argv[i] != '/') 746 }
643 { 747 else
644 quote_file_name (cwd, out); 748 relative = 1;
645 fprintf (out, "/"); 749 }
646 } 750 else if (*argv[i] != '/')
647 751 relative = 1;
648 quote_file_name (argv[i], out); 752
649 fprintf (out, " "); 753 fprintf (out, "-file ");
650 } 754 if (relative)
755 {
756 quote_argument (cwd, out);
757 fprintf (out, "/");
758 }
759 quote_argument (argv[i], out);
760 fprintf (out, " ");
761 }
651 } 762 }
652 else 763 else
653 { 764 {
@@ -655,14 +766,19 @@ To start the server in Emacs, type \"M-x server-start\".\n",
655 { 766 {
656 while ((str = fgets (string, BUFSIZ, stdin))) 767 while ((str = fgets (string, BUFSIZ, stdin)))
657 { 768 {
658 quote_file_name (str, out); 769 if (eval)
770 fprintf (out, "-eval ");
771 else
772 fprintf (out, "-file ");
773 quote_argument (str, out);
659 } 774 }
660 fprintf (out, " "); 775 fprintf (out, " ");
661 } 776 }
662 } 777 }
663 778
664 fprintf (out, "\n"); 779 fprintf (out, "\n");
665 fflush (out); 780 fflush (out);
781 fsync (fileno (out));
666 782
667 /* Maybe wait for an answer. */ 783 /* Maybe wait for an answer. */
668 if (nowait) 784 if (nowait)
@@ -676,44 +792,49 @@ To start the server in Emacs, type \"M-x server-start\".\n",
676 needlf = 2; 792 needlf = 2;
677 } 793 }
678 fflush (stdout); 794 fflush (stdout);
795 fsync (1);
679 796
680 /* Now, wait for an answer and print any messages. */ 797 /* Now, wait for an answer and print any messages. */
681 while ((str = fgets (string, BUFSIZ, in))) 798 while ((str = fgets (string, BUFSIZ, in)))
682 { 799 {
800 char *p = str + strlen (str) - 1;
801 while (p > str && *p == '\n')
802 *p-- = 0;
803
683 if (strprefix ("-good-version ", str)) 804 if (strprefix ("-good-version ", str))
684 { 805 {
685 /* OK, we got the green light. */ 806 /* OK, we got the green light. */
686 } 807 }
687 else if (strprefix ("-bad-version ", str))
688 {
689 if (str[strlen (str) - 1] == '\n')
690 str[strlen (str) - 1] = 0;
691
692 fprintf (stderr, "%s: Version mismatch: Emacs is %s, but we are %s\n",
693 argv[0], str + strlen ("-bad-version "), VERSION);
694 fail ();
695 }
696 else if (strprefix ("-emacs-pid ", str)) 808 else if (strprefix ("-emacs-pid ", str))
697 { 809 {
698 emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10); 810 emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
699 } 811 }
700 else if (strprefix ("-print ", str)) 812 else if (strprefix ("-print ", str))
701 { 813 {
702 if (needlf == 2) 814 str = unquote_argument (str + strlen ("-print "));
815 if (needlf)
703 printf ("\n"); 816 printf ("\n");
704 printf ("%s", str + strlen ("-print ")); 817 printf ("%s", str);
705 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; 818 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
706 } 819 }
707 else if (strprefix ("-error ", str)) 820 else if (strprefix ("-error ", str))
708 { 821 {
709 if (needlf == 2) 822 str = unquote_argument (str + strlen ("-error "));
823 if (needlf)
824 printf ("\n");
825 printf ("*ERROR*: %s", str);
826 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
827 }
828 else if (strprefix ("-suspend ", str))
829 {
830 if (needlf)
710 printf ("\n"); 831 printf ("\n");
711 printf ("*ERROR*: %s", str + strlen ("-print ")); 832 needlf = 0;
712 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; 833 kill (0, SIGSTOP);
713 } 834 }
714 else 835 else
715 { 836 {
716 if (needlf == 2) 837 if (needlf)
717 printf ("\n"); 838 printf ("\n");
718 printf ("*ERROR*: Unknown message: %s", str); 839 printf ("*ERROR*: Unknown message: %s", str);
719 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; 840 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
@@ -723,6 +844,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
723 if (needlf) 844 if (needlf)
724 printf ("\n"); 845 printf ("\n");
725 fflush (stdout); 846 fflush (stdout);
847 fsync (1);
726 848
727 return 0; 849 return 0;
728} 850}
diff --git a/lisp/frame.el b/lisp/frame.el
index 8d76c7b70ba..54bccd93970 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -750,6 +750,22 @@ Otherwise, that variable should be nil."
750 (iconify-frame) 750 (iconify-frame)
751 (make-frame-visible))) 751 (make-frame-visible)))
752 752
753(defun suspend-frame ()
754 "Do whatever is right to suspend the current frame.
755Calls `suspend-emacs' if invoked from the controlling terminal,
756`suspend-tty' from a secondary terminal, and
757`iconify-or-deiconify-frame' from an X frame."
758 (interactive)
759 (let ((type (framep (selected-frame))))
760 (cond
761 ((eq type 'x) (iconify-or-deiconify-frame))
762 ((eq type t)
763 (if (frame-tty-name)
764 (suspend-tty)
765 (suspend-emacs)))
766 (t (suspend-emacs)))))
767
768
753(defun make-frame-names-alist () 769(defun make-frame-names-alist ()
754 (let* ((current-frame (selected-frame)) 770 (let* ((current-frame (selected-frame))
755 (falist 771 (falist
@@ -1374,6 +1390,8 @@ Use Custom to set this variable to get the display updated."
1374(define-key ctl-x-5-map "0" 'delete-frame) 1390(define-key ctl-x-5-map "0" 'delete-frame)
1375(define-key ctl-x-5-map "o" 'other-frame) 1391(define-key ctl-x-5-map "o" 'other-frame)
1376 1392
1393(substitute-key-definition 'suspend-emacs 'suspend-frame global-map)
1394
1377(provide 'frame) 1395(provide 'frame)
1378 1396
1379;;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56 1397;;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56
diff --git a/lisp/server.el b/lisp/server.el
index a1619471e56..aac3da13e4f 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -186,7 +186,7 @@ are done with it in the server.")
186 (with-current-buffer "*server*" 186 (with-current-buffer "*server*"
187 (goto-char (point-max)) 187 (goto-char (point-max))
188 (insert (current-time-string) 188 (insert (current-time-string)
189 (if client (format " %s:" client) " ") 189 (if client (format " %s: " client) " ")
190 string) 190 string)
191 (or (bolp) (newline))))) 191 (or (bolp) (newline)))))
192 192
@@ -227,6 +227,7 @@ are done with it in the server.")
227 (term (nth 1 entry))) 227 (term (nth 1 entry)))
228 (when (equal term tty) 228 (when (equal term tty)
229 (let ((client (assq proc server-clients))) 229 (let ((client (assq proc server-clients)))
230 (server-log (format "server-handle-delete-tty, tty %s" tty) (car client))
230 (setq server-ttys (delq entry server-ttys)) 231 (setq server-ttys (delq entry server-ttys))
231 (delete-process (car client)) 232 (delete-process (car client))
232 (when (assq proc server-clients) 233 (when (assq proc server-clients)
@@ -234,6 +235,16 @@ are done with it in the server.")
234 ;; `emacsclient -t -e '(delete-frame)'' correctly. 235 ;; `emacsclient -t -e '(delete-frame)'' correctly.
235 (setq server-clients (delq client server-clients)))))))) 236 (setq server-clients (delq client server-clients))))))))
236 237
238(defun server-handle-suspend-tty (tty)
239 "Notify the emacsclient process to suspend itself when its tty device is suspended."
240 (dolist (entry server-ttys)
241 (let ((proc (nth 0 entry))
242 (term (nth 1 entry)))
243 (when (equal term tty)
244 (let ((process (car (assq proc server-clients))))
245 (server-log (format "server-handle-suspend-tty, tty %s" tty) process)
246 (process-send-string process "-suspend \n"))))))
247
237(defun server-handle-delete-frame (frame) 248(defun server-handle-delete-frame (frame)
238 "Delete the client connection when the emacsclient frame is deleted." 249 "Delete the client connection when the emacsclient frame is deleted."
239 (dolist (entry server-frames) 250 (dolist (entry server-frames)
@@ -241,6 +252,7 @@ are done with it in the server.")
241 (f (nth 1 entry))) 252 (f (nth 1 entry)))
242 (when (equal frame f) 253 (when (equal frame f)
243 (let ((client (assq proc server-clients))) 254 (let ((client (assq proc server-clients)))
255 (server-log (format "server-handle-delete-frame, frame %s" frame) (car client))
244 (setq server-frames (delq entry server-frames)) 256 (setq server-frames (delq entry server-frames))
245 (delete-process (car client)) 257 (delete-process (car client))
246 (when (assq proc server-clients) 258 (when (assq proc server-clients)
@@ -278,6 +290,19 @@ are done with it in the server.")
278 (t " "))) 290 (t " ")))
279 arg t t)) 291 arg t t))
280 292
293(defun server-quote-arg (arg)
294 "In NAME, insert a & before each &, each space, each newline, and -.
295Change spaces to underscores, too, so that the return value never
296contains a space."
297 (replace-regexp-in-string
298 "[-&\n ]" (lambda (s)
299 (case (aref s 0)
300 (?& "&&")
301 (?- "&-")
302 (?\n "&n")
303 (?\s "&_")))
304 arg t t))
305
281(defun server-ensure-safe-dir (dir) 306(defun server-ensure-safe-dir (dir)
282 "Make sure DIR is a directory with no race-condition issues. 307 "Make sure DIR is a directory with no race-condition issues.
283Creates the directory if necessary and makes sure: 308Creates the directory if necessary and makes sure:
@@ -325,6 +350,7 @@ Prefix arg means just kill any existing server communications subprocess."
325 (server-log (message "Restarting server"))) 350 (server-log (message "Restarting server")))
326 (letf (((default-file-modes) ?\700)) 351 (letf (((default-file-modes) ?\700))
327 (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty) 352 (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty)
353 (add-to-list 'suspend-tty-functions 'server-handle-suspend-tty)
328 (add-to-list 'delete-frame-functions 'server-handle-delete-frame) 354 (add-to-list 'delete-frame-functions 'server-handle-delete-frame)
329 (setq server-process 355 (setq server-process
330 (make-network-process 356 (make-network-process
@@ -358,140 +384,182 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
358 (setq string (concat prev string)) 384 (setq string (concat prev string))
359 (process-put proc 'previous-string nil))) 385 (process-put proc 'previous-string nil)))
360 (condition-case err 386 (condition-case err
361 ;; If the input is multiple lines, 387 (progn
362 ;; process each line individually. 388 ;; If the input is multiple lines,
363 (while (string-match "\n" string) 389 ;; process each line individually.
364 (let ((request (substring string 0 (match-beginning 0))) 390 (while (string-match "\n" string)
365 (coding-system (and default-enable-multibyte-characters 391 (let ((request (substring string 0 (match-beginning 0)))
366 (or file-name-coding-system 392 (coding-system (and default-enable-multibyte-characters
367 default-file-name-coding-system))) 393 (or file-name-coding-system
368 client nowait eval newframe display version-checked 394 default-file-name-coding-system)))
369 registered ; t if the client is already added to server-clients. 395 client nowait newframe display version-checked
370 (files nil) 396 dontkill ; t if the client should not be killed.
371 (lineno 1) 397 registered ; t if the client is already added to server-clients.
372 (columnno 0)) 398 (files nil)
373 ;; Remove this line from STRING. 399 (lineno 1)
374 (setq string (substring string (match-end 0))) 400 (columnno 0))
375 (setq client (cons proc nil)) 401 ;; Remove this line from STRING.
376 (while (string-match "[^ ]* " request) 402 (setq string (substring string (match-end 0)))
377 (let ((arg (substring request (match-beginning 0) (1- (match-end 0))))) 403 (setq client (cons proc nil))
378 (setq request (substring request (match-end 0))) 404 (while (string-match "[^ ]* " request)
379 (cond 405 (let ((arg (substring request (match-beginning 0) (1- (match-end 0)))))
380 ;; Check version numbers. 406 (setq request (substring request (match-end 0)))
381 ((and (equal "-version" arg) (string-match "\\([0-9.]+\\) " request)) 407 (cond
382 (let* ((client-version (match-string 1 request)) 408 ;; Check version numbers.
383 (truncated-emacs-version (substring emacs-version 0 (length client-version)))) 409 ((and (equal "-version" arg) (string-match "\\([0-9.]+\\) " request))
384 (setq request (substring request (match-end 0))) 410 (let* ((client-version (match-string 1 request))
385 (if (equal client-version truncated-emacs-version) 411 (truncated-emacs-version (substring emacs-version 0 (length client-version))))
386 (progn 412 (setq request (substring request (match-end 0)))
387 (process-send-string proc "-good-version \n") 413 (if (equal client-version truncated-emacs-version)
388 (setq version-checked t)) 414 (progn
389 (error (concat "Version mismatch: Emacs is " truncated-emacs-version ", emacsclient is " client-version))))) 415 (process-send-string proc "-good-version \n")
390 416 (setq version-checked t))
391 ((equal "-nowait" arg) (setq nowait t)) 417 (error (concat "Version mismatch: Emacs is " truncated-emacs-version ", emacsclient is " client-version)))))
392 ((equal "-eval" arg) (setq eval t)) 418
393 419 ((equal "-nowait" arg) (setq nowait t))
394 ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request)) 420
395 (setq display (match-string 1 request) 421 ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
396 request (substring request (match-end 0)))) 422 (setq display (match-string 1 request)
397 423 request (substring request (match-end 0))))
398 ;; Open a new X frame. 424
399 ((equal "-window-system" arg) 425 ;; Open a new X frame.
400 (unless version-checked 426 ((equal "-window-system" arg)
401 (error "Protocol error; make sure to use the correct version of emacsclient"))
402 (let ((frame (make-frame-on-display
403 (or display
404 (frame-parameter nil 'display)
405 (getenv "DISPLAY")
406 (error "Please specify display")))))
407 (push (list proc frame) server-frames)
408 (select-frame frame)
409 ;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
410 (push client server-clients)
411 (setq registered t
412 newframe t)))
413
414 ;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
415 ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
416 (let ((tty (server-unquote-arg (match-string 1 request)))
417 (type (server-unquote-arg (match-string 2 request))))
418 (setq request (substring request (match-end 0)))
419 (unless version-checked 427 (unless version-checked
420 (error "Protocol error; make sure to use the correct version of emacsclient")) 428 (error "Protocol error; make sure to use the correct version of emacsclient"))
421 (let ((frame (make-frame-on-tty tty type))) 429 (let ((frame (make-frame-on-display
422 (push (list (car client) (frame-tty-name frame)) server-ttys) 430 (or display
423 (process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n")) 431 (frame-parameter nil 'display)
432 (getenv "DISPLAY")
433 (error "Please specify display")))))
434 (push (list proc frame) server-frames)
424 (select-frame frame) 435 (select-frame frame)
425 ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right. 436 ;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
426 (push client server-clients) 437 (push client server-clients)
427 (setq registered t 438 (setq registered t
428 newframe t)))) 439 newframe t
429 440 dontkill t)))
430 ;; ARG is a line number option. 441
431 ((string-match "\\`\\+[0-9]+\\'" arg) 442 ;; Resume a suspended tty frame.
432 (setq lineno (string-to-int (substring arg 1)))) 443 ((equal "-resume" arg)
433 444 (let ((tty (cadr (assq (car client) server-ttys))))
434 ;; ARG is line number:column option. 445 (setq dontkill t)
435 ((string-match "\\`\\+\\([0-9]+\\):\\([0-9]+\\)\\'" arg) 446 (when tty (resume-tty tty))))
436 (setq lineno (string-to-int (match-string 1 arg)) 447
437 columnno (string-to-int (match-string 2 arg)))) 448 ;; Suspend the client's frame. (In case we get out of
438 449 ;; sync, and a C-z sends a SIGTSTP to emacsclient.)
439 ;; ARG is a filename or a Lisp expression. 450 ((equal "-suspend" arg)
440 (t 451 (let ((tty (cadr (assq (car client) server-ttys))))
441 ;; Undo the quoting that emacsclient does 452 (setq dontkill t)
442 ;; for certain special characters. 453 (when tty (suspend-tty tty))))
443 (setq arg (server-unquote-arg arg)) 454
444 ;; Now decode the file name if necessary. 455 ;; Noop; useful for debugging emacsclient.
445 (if coding-system 456 ((and (equal "-ignore" arg) (string-match "\\([^ ]*\\) " request))
446 (setq arg (decode-coding-string arg coding-system))) 457 (setq dontkill t
447 (unless version-checked 458 request (substring request (match-end 0))))
448 (error "Protocol error; make sure to use the correct version of emacsclient")) 459
449 (if eval 460 ;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
450 ;; ARG is a Lisp expression. 461 ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
451 (let ((v (eval (car (read-from-string arg))))) 462 (let ((tty (server-unquote-arg (match-string 1 request)))
463 (type (server-unquote-arg (match-string 2 request))))
464 (setq request (substring request (match-end 0)))
465 (unless version-checked
466 (error "Protocol error; make sure to use the correct version of emacsclient"))
467 (let ((frame (make-frame-on-tty tty type)))
468 (push (list (car client) (frame-tty-name frame)) server-ttys)
469 (process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n"))
470 (select-frame frame)
471 ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right.
472 (push client server-clients)
473 (setq registered t
474 dontkill t
475 newframe t))))
476
477 ;; ARG is a line number option.
478 ((and (equal "-position" arg) (string-match "\\(\\+[0-9]+\\) " request))
479 (setq request (substring request (match-end 0))
480 lineno (string-to-int (substring (match-string 1 request) 1))))
481
482 ;; ARG is line number:column option.
483 ((and (equal "-position" arg) (string-match "\\+\\([0-9]+\\):\\([0-9]+\\) " request))
484 (setq request (substring request (match-end 0))
485 lineno (string-to-int (match-string 1 request))
486 columnno (string-to-int (match-string 2 request))))
487
488 ;; ARG is a file to load.
489 ((and (equal "-file" arg) (string-match "\\([^ ]+\\) " request))
490 (let ((file (server-unquote-arg (match-string 1 request))))
491 (setq request (substring request (match-end 0)))
492 (if coding-system
493 (setq file (decode-coding-string file coding-system)))
494 (setq file (command-line-normalize-file-name file))
495 (push (list file lineno columnno) files))
496 (setq lineno 1
497 columnno 0))
498
499 ;; ARG is a Lisp expression.
500 ((and (equal "-eval" arg) (string-match "\\([^ ]+\\) " request))
501 (let ((expr (server-unquote-arg (match-string 1 request))))
502 (setq request (substring request (match-end 0)))
503 (if coding-system
504 (setq expr (decode-coding-string expr coding-system)))
505 (let ((v (eval (car (read-from-string expr)))))
452 (when (and (not newframe) v) 506 (when (and (not newframe) v)
453 (with-temp-buffer 507 (with-temp-buffer
454 (let ((standard-output (current-buffer))) 508 (let ((standard-output (current-buffer)))
455 (pp v) 509 (pp v)
456 (process-send-string proc "-print ") 510 (process-send-string proc "-print ")
457 (process-send-region proc (point-min) (point-max)))))) 511 (process-send-string
458 ;; ARG is a file name. 512 proc (server-quote-arg
459 ;; Collapse multiple slashes to single slashes. 513 (buffer-substring-no-properties (point-min)
460 (setq arg (command-line-normalize-file-name arg)) 514 (point-max))))
461 (push (list arg lineno columnno) files)) 515 (process-send-string proc "\n")))))
462 (setq lineno 1) 516 (setq lineno 1
463 (setq columnno 0))))) 517 columnno 0)))
464 518
465 (if (not version-checked) 519 ;; Unknown command.
466 (error "Protocol error; make sure to use the correct version of emacsclient") 520 (t (error "Unknown command: %s" arg)))))
521
467 (when files 522 (when files
468 (run-hooks 'pre-command-hook) 523 (run-hooks 'pre-command-hook)
469 (server-visit-files files client nowait) 524 (server-visit-files files client nowait)
470 (run-hooks 'post-command-hook)) 525 (run-hooks 'post-command-hook))
526
471 ;; CLIENT is now a list (CLIENTNUM BUFFERS...) 527 ;; CLIENT is now a list (CLIENTNUM BUFFERS...)
472 (if (and (not newframe) (null (cdr client))) 528
473 ;; This client is empty; get rid of it immediately. 529 ;; Delete the client if necessary.
474 (progn 530 (cond
475 (delete-process proc) 531 ;; Client requested nowait; return immediately.
476 (server-log "Close empty client" proc)) 532 (nowait
477 ;; We visited some buffer for this client. 533 (delete-process proc)
478 (or nowait registered (push client server-clients)) 534 (server-log "Close nowait client" proc))
479 (unless (or isearch-mode (minibufferp)) 535 ;; This client is empty; get rid of it immediately.
480 (if (and newframe (null (cdr client))) 536 ((and (not dontkill) (null (cdr client)))
481 (message (substitute-command-keys 537 (delete-process proc)
482 "When done with this frame, type \\[delete-frame]")) 538 (server-log "Close empty client" proc))
483 (server-switch-buffer (nth 1 client)) 539 ((not registered)
484 (run-hooks 'server-switch-hook) 540 (push client server-clients)))
485 (unless nowait 541
486 (message (substitute-command-keys 542 ;; We visited some buffer for this client.
487 "When done with a buffer, type \\[server-edit]")))))))) 543 (cond
544 ((or isearch-mode (minibufferp))
545 nil)
546 ((and newframe (null (cdr client)))
547 (message (substitute-command-keys
548 "When done with this frame, type \\[delete-frame]")))
549 ((not (null (cdr client)))
550 (server-switch-buffer (nth 1 client))
551 (run-hooks 'server-switch-hook)
552 (unless nowait
553 (message (substitute-command-keys
554 "When done with a buffer, type \\[server-edit]")))))))
555
488 ;; Save for later any partial line that remains. 556 ;; Save for later any partial line that remains.
489 (when (> (length string) 0) 557 (when (> (length string) 0)
490 (process-put proc 'previous-string string))) 558 (process-put proc 'previous-string string)))
491 ;; condition-case 559 ;; condition-case
492 (error (ignore-errors 560 (error (ignore-errors
493 (process-send-string 561 (process-send-string
494 proc (concat "-error " (error-message-string err))) 562 proc (concat "-error " (server-quote-arg (error-message-string err))))
495 (setq string "") 563 (setq string "")
496 (server-log (error-message-string err) proc) 564 (server-log (error-message-string err) proc)
497 (delete-process proc))))) 565 (delete-process proc)))))
diff --git a/lisp/term/x-win.el b/lisp/term/x-win.el
index e09285e86c1..da5ac04a6c9 100644
--- a/lisp/term/x-win.el
+++ b/lisp/term/x-win.el
@@ -2442,11 +2442,7 @@ order until succeed.")
2442 (if res-selection-timeout 2442 (if res-selection-timeout
2443 (setq x-selection-timeout (string-to-number res-selection-timeout)))) 2443 (setq x-selection-timeout (string-to-number res-selection-timeout))))
2444 2444
2445 ;; XXX This is wrong in general with multi-tty support. 2445 ;; Don't let Emacs suspend under X.
2446 (substitute-key-definition 'suspend-emacs 'iconify-or-deiconify-frame
2447 global-map)
2448
2449 ;; XXX This is wrong in general with multi-tty support.
2450 (add-hook 'suspend-hook 'x-win-suspend-error) 2446 (add-hook 'suspend-hook 'x-win-suspend-error)
2451 2447
2452 ;; Arrange for the kill and yank functions to set and check the clipboard. 2448 ;; Arrange for the kill and yank functions to set and check the clipboard.
diff --git a/src/cm.c b/src/cm.c
index 5ce03483b06..9f9cc0e0a34 100644
--- a/src/cm.c
+++ b/src/cm.c
@@ -64,9 +64,9 @@ int
64cmputc (c) 64cmputc (c)
65 char c; 65 char c;
66{ 66{
67 if (TTY_TERMSCRIPT (current_tty)) 67 if (current_tty->termscript)
68 putc (c & 0177, TTY_TERMSCRIPT (current_tty)); 68 putc (c & 0177, current_tty->termscript);
69 putc (c & 0177, TTY_OUTPUT (current_tty)); 69 putc (c & 0177, current_tty->output);
70 return c; 70 return c;
71} 71}
72 72
@@ -136,12 +136,12 @@ cmcheckmagic (struct tty_display_info *tty)
136 { 136 {
137 if (!MagicWrap (tty) || curY (tty) >= FrameRows (tty) - 1) 137 if (!MagicWrap (tty) || curY (tty) >= FrameRows (tty) - 1)
138 abort (); 138 abort ();
139 if (TTY_TERMSCRIPT (tty)) 139 if (tty->termscript)
140 putc ('\r', TTY_TERMSCRIPT (tty)); 140 putc ('\r', tty->termscript);
141 putc ('\r', TTY_OUTPUT (tty)); 141 putc ('\r', tty->output);
142 if (TTY_TERMSCRIPT (tty)) 142 if (tty->termscript)
143 putc ('\n', TTY_TERMSCRIPT (tty)); 143 putc ('\n', tty->termscript);
144 putc ('\n', TTY_OUTPUT (tty)); 144 putc ('\n', tty->output);
145 curX (tty) = 0; 145 curX (tty) = 0;
146 curY (tty)++; 146 curY (tty)++;
147 } 147 }
diff --git a/src/dispnew.c b/src/dispnew.c
index aaf3c440f34..8a3d7013c3e 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3316,7 +3316,7 @@ DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
3316 clear_current_matrices (f); 3316 clear_current_matrices (f);
3317 update_end (f); 3317 update_end (f);
3318 if (FRAME_TERMCAP_P (f)) 3318 if (FRAME_TERMCAP_P (f))
3319 fflush (TTY_OUTPUT (FRAME_TTY (f))); 3319 fflush (FRAME_TTY (f)->output);
3320 windows_or_buffers_changed++; 3320 windows_or_buffers_changed++;
3321 /* Mark all windows as inaccurate, so that every window will have 3321 /* Mark all windows as inaccurate, so that every window will have
3322 its redisplay done. */ 3322 its redisplay done. */
@@ -3659,7 +3659,7 @@ direct_output_for_insert (g)
3659 update_end (f); 3659 update_end (f);
3660 updated_row = NULL; 3660 updated_row = NULL;
3661 if (FRAME_TERMCAP_P (f)) 3661 if (FRAME_TERMCAP_P (f))
3662 fflush (TTY_OUTPUT (FRAME_TTY (f))); 3662 fflush (FRAME_TTY (f)->output);
3663 3663
3664 TRACE ((stderr, "direct output for insert\n")); 3664 TRACE ((stderr, "direct output for insert\n"));
3665 mark_window_display_accurate (it.window, 1); 3665 mark_window_display_accurate (it.window, 1);
@@ -3751,7 +3751,7 @@ direct_output_forward_char (n)
3751 } 3751 }
3752 3752
3753 if (FRAME_TERMCAP_P (f)) 3753 if (FRAME_TERMCAP_P (f))
3754 fflush (TTY_OUTPUT (FRAME_TTY (f))); 3754 fflush (FRAME_TTY (f)->output);
3755 redisplay_performed_directly_p = 1; 3755 redisplay_performed_directly_p = 1;
3756 return 1; 3756 return 1;
3757} 3757}
@@ -3849,9 +3849,9 @@ update_frame (f, force_p, inhibit_hairy_id_p)
3849 3849
3850 if (FRAME_TERMCAP_P (f)) 3850 if (FRAME_TERMCAP_P (f))
3851 { 3851 {
3852 if (TTY_TERMSCRIPT (FRAME_TTY (f))) 3852 if (FRAME_TTY (f)->termscript)
3853 fflush (TTY_TERMSCRIPT (FRAME_TTY (f))); 3853 fflush (FRAME_TTY (f)->termscript);
3854 fflush (TTY_OUTPUT (FRAME_TTY (f))); 3854 fflush (FRAME_TTY (f)->output);
3855 } 3855 }
3856 3856
3857 /* Check window matrices for lost pointers. */ 3857 /* Check window matrices for lost pointers. */
@@ -5133,18 +5133,18 @@ update_frame_1 (f, force_p, inhibit_id_p)
5133 Also flush out if likely to have more than 1k buffered 5133 Also flush out if likely to have more than 1k buffered
5134 otherwise. I'm told that some telnet connections get 5134 otherwise. I'm told that some telnet connections get
5135 really screwed by more than 1k output at once. */ 5135 really screwed by more than 1k output at once. */
5136 int outq = PENDING_OUTPUT_COUNT (TTY_OUTPUT (FRAME_TTY (f))); 5136 int outq = PENDING_OUTPUT_COUNT (FRAME_TTY (f)->output);
5137 if (outq > 900 5137 if (outq > 900
5138 || (outq > 20 && ((i - 1) % preempt_count == 0))) 5138 || (outq > 20 && ((i - 1) % preempt_count == 0)))
5139 { 5139 {
5140 fflush (TTY_OUTPUT (FRAME_TTY (f))); 5140 fflush (FRAME_TTY (f)->output);
5141 if (preempt_count == 1) 5141 if (preempt_count == 1)
5142 { 5142 {
5143#ifdef EMACS_OUTQSIZE 5143#ifdef EMACS_OUTQSIZE
5144 if (EMACS_OUTQSIZE (0, &outq) < 0) 5144 if (EMACS_OUTQSIZE (0, &outq) < 0)
5145 /* Probably not a tty. Ignore the error and reset 5145 /* Probably not a tty. Ignore the error and reset
5146 the outq count. */ 5146 the outq count. */
5147 outq = PENDING_OUTPUT_COUNT (TTY_OUTPUT (FRAME_TTY (f))); 5147 outq = PENDING_OUTPUT_COUNT (FRAME_TTY (f->output));
5148#endif 5148#endif
5149 outq *= 10; 5149 outq *= 10;
5150 if (baud_rate <= outq && baud_rate > 0) 5150 if (baud_rate <= outq && baud_rate > 0)
@@ -5999,7 +5999,7 @@ window_change_signal (signalnum) /* If we don't have an argument, */
5999 if (! tty->term_initted) 5999 if (! tty->term_initted)
6000 continue; 6000 continue;
6001 6001
6002 get_tty_size (fileno (TTY_INPUT (tty)), &width, &height); 6002 get_tty_size (fileno (tty->input), &width, &height);
6003 6003
6004 { 6004 {
6005 Lisp_Object tail, frame; 6005 Lisp_Object tail, frame;
@@ -6211,15 +6211,22 @@ FILE = nil means just close any termscript file currently open. */)
6211 (file) 6211 (file)
6212 Lisp_Object file; 6212 Lisp_Object file;
6213{ 6213{
6214 if (TTY_TERMSCRIPT (CURTTY ()) != 0) 6214 struct tty_display_info *tty;
6215 fclose (TTY_TERMSCRIPT (CURTTY ())); 6215
6216 TTY_TERMSCRIPT (CURTTY ()) = 0; 6216 if (! FRAME_TERMCAP_P (SELECTED_FRAME ()))
6217 error ("Current frame is not on a tty device");
6218
6219 tty = CURTTY ();
6220
6221 if (tty->termscript != 0)
6222 fclose (tty->termscript);
6223 tty->termscript = 0;
6217 6224
6218 if (! NILP (file)) 6225 if (! NILP (file))
6219 { 6226 {
6220 file = Fexpand_file_name (file, Qnil); 6227 file = Fexpand_file_name (file, Qnil);
6221 TTY_TERMSCRIPT (CURTTY ()) = fopen (SDATA (file), "w"); 6228 tty->termscript = fopen (SDATA (file), "w");
6222 if (TTY_TERMSCRIPT (CURTTY ()) == 0) 6229 if (tty->termscript == 0)
6223 report_file_error ("Opening termscript", Fcons (file, Qnil)); 6230 report_file_error ("Opening termscript", Fcons (file, Qnil));
6224 } 6231 }
6225 return Qnil; 6232 return Qnil;
@@ -6233,20 +6240,23 @@ Control characters in STRING will have terminal-dependent effects. */)
6233 (string) 6240 (string)
6234 Lisp_Object string; 6241 Lisp_Object string;
6235{ 6242{
6243 struct tty_display_info *tty;
6244
6236 /* ??? Perhaps we should do something special for multibyte strings here. */ 6245 /* ??? Perhaps we should do something special for multibyte strings here. */
6237 CHECK_STRING (string); 6246 CHECK_STRING (string);
6247
6238 if (! FRAME_TERMCAP_P (SELECTED_FRAME ())) 6248 if (! FRAME_TERMCAP_P (SELECTED_FRAME ()))
6239 error ("Current frame is not on a tty device"); 6249 error ("Current frame is not on a tty device");
6250
6251 tty = CURTTY ();
6240 6252
6241 if (TTY_TERMSCRIPT (CURTTY ())) 6253 if (tty->termscript)
6242 { 6254 {
6243 fwrite (SDATA (string), 1, SBYTES (string), 6255 fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
6244 TTY_TERMSCRIPT (CURTTY ())); 6256 fflush (tty->termscript);
6245 fflush (TTY_TERMSCRIPT (CURTTY ()));
6246 } 6257 }
6247 fwrite (SDATA (string), 1, SBYTES (string), 6258 fwrite (SDATA (string), 1, SBYTES (string), tty->output);
6248 TTY_OUTPUT (CURTTY ())); 6259 fflush (tty->output);
6249 fflush (TTY_OUTPUT (CURTTY ()));
6250 return Qnil; 6260 return Qnil;
6251} 6261}
6252 6262
@@ -6265,7 +6275,7 @@ terminate any keyboard macro currently executing. */)
6265 else 6275 else
6266 ring_bell (); 6276 ring_bell ();
6267 if (FRAME_TERMCAP_P (XFRAME (selected_frame))) 6277 if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
6268 fflush (TTY_OUTPUT (CURTTY ())); 6278 fflush (CURTTY ()->output);
6269 } 6279 }
6270 else 6280 else
6271 bitch_at_user (); 6281 bitch_at_user ();
@@ -6283,7 +6293,7 @@ bitch_at_user ()
6283 else 6293 else
6284 ring_bell (); 6294 ring_bell ();
6285 if (FRAME_TERMCAP_P (XFRAME (selected_frame))) 6295 if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
6286 fflush (TTY_OUTPUT (CURTTY ())); 6296 fflush (CURTTY ()->output);
6287} 6297}
6288 6298
6289 6299
diff --git a/src/frame.c b/src/frame.c
index 8ffabfa8b89..c7b5491500f 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -667,7 +667,8 @@ and the `tty-type' parameter specifies the terminal type. Example:
667 667
668 (make-terminal-frame '((tty . "/dev/pts/5") (tty-type . "xterm"))) 668 (make-terminal-frame '((tty . "/dev/pts/5") (tty-type . "xterm")))
669 669
670Note that changing the size of one terminal frame automatically affects all. */) 670Note that changing the size of one terminal frame automatically
671affects all frames on the same terminal device. */)
671 (parms) 672 (parms)
672 Lisp_Object parms; 673 Lisp_Object parms;
673{ 674{
@@ -742,7 +743,7 @@ Note that changing the size of one terminal frame automatically affects all. */
742 743
743 { 744 {
744 int width, height; 745 int width, height;
745 get_tty_size (fileno (TTY_INPUT (FRAME_TTY (f))), &width, &height); 746 get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height);
746 change_frame_size (f, height, width, 0, 0, 0); 747 change_frame_size (f, height, width, 0, 0, 0);
747 } 748 }
748 749
diff --git a/src/keyboard.c b/src/keyboard.c
index 2c6edc68f99..5bcd53a260f 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -6704,10 +6704,13 @@ tty_read_avail_input (struct display *display,
6704 if (! tty->term_initted) /* In case we get called during bootstrap. */ 6704 if (! tty->term_initted) /* In case we get called during bootstrap. */
6705 return 0; 6705 return 0;
6706 6706
6707 if (! tty->input)
6708 return 0; /* The terminal is suspended. */
6709
6707 /* Determine how many characters we should *try* to read. */ 6710 /* Determine how many characters we should *try* to read. */
6708#ifdef FIONREAD 6711#ifdef FIONREAD
6709 /* Find out how much input is available. */ 6712 /* Find out how much input is available. */
6710 if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0) 6713 if (ioctl (fileno (tty->input), FIONREAD, &n_to_read) < 0)
6711 { 6714 {
6712 if (! noninteractive) 6715 if (! noninteractive)
6713 return -2; /* Close this display. */ 6716 return -2; /* Close this display. */
@@ -6722,7 +6725,7 @@ tty_read_avail_input (struct display *display,
6722#if defined (USG) || defined (DGUX) || defined(CYGWIN) 6725#if defined (USG) || defined (DGUX) || defined(CYGWIN)
6723 /* Read some input if available, but don't wait. */ 6726 /* Read some input if available, but don't wait. */
6724 n_to_read = sizeof cbuf; 6727 n_to_read = sizeof cbuf;
6725 fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY); 6728 fcntl (fileno (tty->input), F_SETFL, O_NDELAY);
6726#else 6729#else
6727 you lose; 6730 you lose;
6728#endif 6731#endif
@@ -6732,7 +6735,7 @@ tty_read_avail_input (struct display *display,
6732 NREAD is set to the number of chars read. */ 6735 NREAD is set to the number of chars read. */
6733 do 6736 do
6734 { 6737 {
6735 nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read); 6738 nread = emacs_read (fileno (tty->input), cbuf, n_to_read);
6736 /* POSIX infers that processes which are not in the session leader's 6739 /* POSIX infers that processes which are not in the session leader's
6737 process group won't get SIGHUP's at logout time. BSDI adheres to 6740 process group won't get SIGHUP's at logout time. BSDI adheres to
6738 this part standard and returns -1 from read (0) with errno==EIO 6741 this part standard and returns -1 from read (0) with errno==EIO
@@ -6770,7 +6773,7 @@ tty_read_avail_input (struct display *display,
6770 6773
6771#ifndef FIONREAD 6774#ifndef FIONREAD
6772#if defined (USG) || defined (DGUX) || defined (CYGWIN) 6775#if defined (USG) || defined (DGUX) || defined (CYGWIN)
6773 fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0); 6776 fcntl (fileno (tty->input), F_SETFL, 0);
6774#endif /* USG or DGUX or CYGWIN */ 6777#endif /* USG or DGUX or CYGWIN */
6775#endif /* no FIONREAD */ 6778#endif /* no FIONREAD */
6776 6779
@@ -10168,7 +10171,7 @@ On such systems, Emacs starts a subshell instead of suspending. */)
10168 call1 (Vrun_hooks, intern ("suspend-hook")); 10171 call1 (Vrun_hooks, intern ("suspend-hook"));
10169 10172
10170 GCPRO1 (stuffstring); 10173 GCPRO1 (stuffstring);
10171 get_tty_size (fileno (TTY_INPUT (CURTTY ())), &old_width, &old_height); 10174 get_tty_size (fileno (CURTTY ()->input), &old_width, &old_height);
10172 reset_all_sys_modes (); 10175 reset_all_sys_modes ();
10173 /* sys_suspend can get an error if it tries to fork a subshell 10176 /* sys_suspend can get an error if it tries to fork a subshell
10174 and the system resources aren't available for that. */ 10177 and the system resources aren't available for that. */
@@ -10184,7 +10187,7 @@ On such systems, Emacs starts a subshell instead of suspending. */)
10184 /* Check if terminal/window size has changed. 10187 /* Check if terminal/window size has changed.
10185 Note that this is not useful when we are running directly 10188 Note that this is not useful when we are running directly
10186 with a window system; but suspend should be disabled in that case. */ 10189 with a window system; but suspend should be disabled in that case. */
10187 get_tty_size (fileno (TTY_INPUT (CURTTY ())), &width, &height); 10190 get_tty_size (fileno (CURTTY ()->input), &width, &height);
10188 if (width != old_width || height != old_height) 10191 if (width != old_width || height != old_height)
10189 change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0); 10192 change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0);
10190 10193
diff --git a/src/sysdep.c b/src/sysdep.c
index febf59253e1..d4693f99a94 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -274,7 +274,7 @@ discard_tty_input ()
274 274
275#ifdef VMS 275#ifdef VMS
276 end_kbd_input (); 276 end_kbd_input ();
277 SYS$QIOW (0, fileno (TTY_INPUT (CURTTY())), IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0, 277 SYS$QIOW (0, fileno (CURTTY()->input), IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
278 &buf.main, 0, 0, terminator_mask, 0, 0); 278 &buf.main, 0, 0, terminator_mask, 0, 0);
279 queue_kbd_input (); 279 queue_kbd_input ();
280#else /* not VMS */ 280#else /* not VMS */
@@ -284,7 +284,8 @@ discard_tty_input ()
284 for (tty = tty_list; tty; tty = tty->next) 284 for (tty = tty_list; tty; tty = tty->next)
285 { 285 {
286 int zero = 0; 286 int zero = 0;
287 ioctl (fileno (TTY_INPUT (tty)), TIOCFLUSH, &zero); 287 if (tty->input)
288 ioctl (fileno (tty->input), TIOCFLUSH, &zero);
288 } 289 }
289 } 290 }
290#else /* not Apollo */ 291#else /* not Apollo */
@@ -296,8 +297,11 @@ discard_tty_input ()
296 struct tty_display_info *tty; 297 struct tty_display_info *tty;
297 for (tty = tty_list; tty; tty = tty->next) 298 for (tty = tty_list; tty; tty = tty->next)
298 { 299 {
299 EMACS_GET_TTY (fileno (TTY_INPUT (tty)), &buf); 300 if (tty->input) /* Is the device suspended? */
300 EMACS_SET_TTY (fileno (TTY_INPUT (tty)), &buf, 0); 301 {
302 EMACS_GET_TTY (fileno (tty->input), &buf);
303 EMACS_SET_TTY (fileno (tty->input), &buf, 0);
304 }
301 } 305 }
302 } 306 }
303#endif /* not MSDOS */ 307#endif /* not MSDOS */
@@ -322,7 +326,7 @@ stuff_char (char c)
322 326
323/* Should perhaps error if in batch mode */ 327/* Should perhaps error if in batch mode */
324#ifdef TIOCSTI 328#ifdef TIOCSTI
325 ioctl (fileno (TTY_INPUT (CURTTY())), TIOCSTI, &c); 329 ioctl (fileno (CURTTY()->input), TIOCSTI, &c);
326#else /* no TIOCSTI */ 330#else /* no TIOCSTI */
327 error ("Cannot stuff terminal input characters in this version of Unix"); 331 error ("Cannot stuff terminal input characters in this version of Unix");
328#endif /* no TIOCSTI */ 332#endif /* no TIOCSTI */
@@ -1005,7 +1009,7 @@ request_sigio ()
1005 return; 1009 return;
1006 1010
1007 /* XXX CURTTY() is bogus here. */ 1011 /* XXX CURTTY() is bogus here. */
1008 ioctl (fileno (TTY_INPUT (CURTTY ())), FIOASYNC, &on); 1012 ioctl (fileno (CURTTY ()->input), FIOASYNC, &on);
1009 interrupts_deferred = 0; 1013 interrupts_deferred = 0;
1010} 1014}
1011 1015
@@ -1018,7 +1022,7 @@ unrequest_sigio ()
1018 return; 1022 return;
1019 1023
1020 /* XXX CURTTY() is bogus here. */ 1024 /* XXX CURTTY() is bogus here. */
1021 ioctl (fileno (TTY_INPUT (CURTTY ())), FIOASYNC, &off); 1025 ioctl (fileno (CURTTY ()->input), FIOASYNC, &off);
1022 interrupts_deferred = 1; 1026 interrupts_deferred = 1;
1023} 1027}
1024 1028
@@ -1366,6 +1370,9 @@ nil means don't delete them until `list-processes' is run. */);
1366 if (noninteractive) 1370 if (noninteractive)
1367 return; 1371 return;
1368 1372
1373 if (!tty_out->output)
1374 return; /* The tty is suspended. */
1375
1369#ifdef VMS 1376#ifdef VMS
1370 if (!input_ef) 1377 if (!input_ef)
1371 input_ef = get_kbd_event_flag (); 1378 input_ef = get_kbd_event_flag ();
@@ -1404,13 +1411,13 @@ nil means don't delete them until `list-processes' is run. */);
1404 unconditionally will not cause any problems. */ 1411 unconditionally will not cause any problems. */
1405 if (! read_socket_hook && EQ (Vinitial_window_system, Qnil)) 1412 if (! read_socket_hook && EQ (Vinitial_window_system, Qnil))
1406#endif 1413#endif
1407 narrow_foreground_group (fileno (TTY_INPUT (tty_out))); 1414 narrow_foreground_group (fileno (tty_out->input));
1408#endif 1415#endif
1409 1416
1410 if (! tty_out->old_tty) 1417 if (! tty_out->old_tty)
1411 tty_out->old_tty = (struct emacs_tty *) xmalloc (sizeof (struct emacs_tty)); 1418 tty_out->old_tty = (struct emacs_tty *) xmalloc (sizeof (struct emacs_tty));
1412 1419
1413 EMACS_GET_TTY (fileno (TTY_INPUT (tty_out)), tty_out->old_tty); 1420 EMACS_GET_TTY (fileno (tty_out->input), tty_out->old_tty);
1414 1421
1415 tty = *tty_out->old_tty; 1422 tty = *tty_out->old_tty;
1416 1423
@@ -1626,23 +1633,23 @@ nil means don't delete them until `list-processes' is run. */);
1626 dos_ttraw (); 1633 dos_ttraw ();
1627#endif 1634#endif
1628 1635
1629 EMACS_SET_TTY (fileno (TTY_INPUT (tty_out)), &tty, 0); 1636 EMACS_SET_TTY (fileno (tty_out->input), &tty, 0);
1630 1637
1631 /* This code added to insure that, if flow-control is not to be used, 1638 /* This code added to insure that, if flow-control is not to be used,
1632 we have an unlocked terminal at the start. */ 1639 we have an unlocked terminal at the start. */
1633 1640
1634#ifdef TCXONC 1641#ifdef TCXONC
1635 if (!tty_out->flow_control) ioctl (fileno (TTY_INPUT (tty_out)), TCXONC, 1); 1642 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1);
1636#endif 1643#endif
1637#ifndef APOLLO 1644#ifndef APOLLO
1638#ifdef TIOCSTART 1645#ifdef TIOCSTART
1639 if (!tty_out->flow_control) ioctl (fileno (TTY_INPUT (tty_out)), TIOCSTART, 0); 1646 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0);
1640#endif 1647#endif
1641#endif 1648#endif
1642 1649
1643#if defined (HAVE_TERMIOS) || defined (HPUX9) 1650#if defined (HAVE_TERMIOS) || defined (HPUX9)
1644#ifdef TCOON 1651#ifdef TCOON
1645 if (!tty_out->flow_control) tcflow (fileno (TTY_INPUT (tty_out)), TCOON); 1652 if (!tty_out->flow_control) tcflow (fileno (tty_out->input), TCOON);
1646#endif 1653#endif
1647#endif 1654#endif
1648 1655
@@ -1662,7 +1669,7 @@ nil means don't delete them until `list-processes' is run. */);
1662 1669
1663#ifdef VMS 1670#ifdef VMS
1664/* Appears to do nothing when in PASTHRU mode. 1671/* Appears to do nothing when in PASTHRU mode.
1665 SYS$QIOW (0, fileno (TTY_INPUT (tty_out)), IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0, 1672 SYS$QIOW (0, fileno (tty_out->input), IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
1666 interrupt_signal, oob_chars, 0, 0, 0, 0); 1673 interrupt_signal, oob_chars, 0, 0, 0, 0);
1667*/ 1674*/
1668 queue_kbd_input (0); 1675 queue_kbd_input (0);
@@ -1673,10 +1680,10 @@ nil means don't delete them until `list-processes' is run. */);
1673#ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */ 1680#ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
1674 if (interrupt_input) 1681 if (interrupt_input)
1675 { 1682 {
1676 old_fcntl_owner[fileno (TTY_INPUT (tty_out))] = 1683 old_fcntl_owner[fileno (tty_out->input)] =
1677 fcntl (fileno (TTY_INPUT (tty_out)), F_GETOWN, 0); 1684 fcntl (fileno (tty_out->input), F_GETOWN, 0);
1678 fcntl (fileno (TTY_INPUT (tty_out)), F_SETOWN, getpid ()); 1685 fcntl (fileno (tty_out->input), F_SETOWN, getpid ());
1679 init_sigio (fileno (TTY_INPUT (tty_out))); 1686 init_sigio (fileno (tty_out->input));
1680 } 1687 }
1681#endif /* F_GETOWN */ 1688#endif /* F_GETOWN */
1682#endif /* F_SETOWN_BUG */ 1689#endif /* F_SETOWN_BUG */
@@ -1684,7 +1691,7 @@ nil means don't delete them until `list-processes' is run. */);
1684 1691
1685#ifdef BSD4_1 1692#ifdef BSD4_1
1686 if (interrupt_input) 1693 if (interrupt_input)
1687 init_sigio (fileno (TTY_INPUT (tty_out))); 1694 init_sigio (fileno (tty_out->input));
1688#endif 1695#endif
1689 1696
1690#ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */ 1697#ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */
@@ -1694,9 +1701,9 @@ nil means don't delete them until `list-processes' is run. */);
1694 /* This symbol is defined on recent USG systems. 1701 /* This symbol is defined on recent USG systems.
1695 Someone says without this call USG won't really buffer the file 1702 Someone says without this call USG won't really buffer the file
1696 even with a call to setbuf. */ 1703 even with a call to setbuf. */
1697 setvbuf (TTY_OUTPUT (tty_out), (char *) _sobuf, _IOFBF, sizeof _sobuf); 1704 setvbuf (tty_out->output, (char *) _sobuf, _IOFBF, sizeof _sobuf);
1698#else 1705#else
1699 setbuf (TTY_OUTPUT (tty_out), (char *) _sobuf); 1706 setbuf (tty_out->output, (char *) _sobuf);
1700#endif 1707#endif
1701 1708
1702 tty_set_terminal_modes (tty_out->display); 1709 tty_set_terminal_modes (tty_out->display);
@@ -1867,10 +1874,13 @@ reset_sys_modes (tty_out)
1867 if (!tty_out->term_initted) 1874 if (!tty_out->term_initted)
1868 return; 1875 return;
1869 1876
1877 if (!tty_out->output)
1878 return; /* The tty is suspended. */
1879
1870 /* Go to and clear the last line of the terminal. */ 1880 /* Go to and clear the last line of the terminal. */
1871 1881
1872 cmgoto (tty_out, FrameRows (tty_out) - 1, 0); 1882 cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
1873 1883
1874 /* Code adapted from tty_clear_end_of_line. */ 1884 /* Code adapted from tty_clear_end_of_line. */
1875 if (tty_out->TS_clr_line) 1885 if (tty_out->TS_clr_line)
1876 { 1886 {
@@ -1880,13 +1890,13 @@ reset_sys_modes (tty_out)
1880 { /* have to do it the hard way */ 1890 { /* have to do it the hard way */
1881 int i; 1891 int i;
1882 turn_off_insert (tty_out); 1892 turn_off_insert (tty_out);
1883 1893
1884 for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++) 1894 for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++)
1885 { 1895 {
1886 fputc (' ', TTY_OUTPUT (tty_out)); 1896 fputc (' ', tty_out->output);
1887 } 1897 }
1888 } 1898 }
1889 1899
1890 cmgoto (tty_out, FrameRows (tty_out) - 1, 0); 1900 cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
1891 fflush (tty_out->output); 1901 fflush (tty_out->output);
1892 1902
@@ -1902,11 +1912,11 @@ reset_sys_modes (tty_out)
1902#endif 1912#endif
1903 1913
1904 tty_reset_terminal_modes (tty_out->display); 1914 tty_reset_terminal_modes (tty_out->display);
1905 fflush (TTY_OUTPUT (tty_out)); 1915 fflush (tty_out->output);
1906#ifdef BSD_SYSTEM 1916#ifdef BSD_SYSTEM
1907#ifndef BSD4_1 1917#ifndef BSD4_1
1908 /* Avoid possible loss of output when changing terminal modes. */ 1918 /* Avoid possible loss of output when changing terminal modes. */
1909 fsync (fileno (TTY_OUTPUT (tty_out))); 1919 fsync (fileno (tty_out->output));
1910#endif 1920#endif
1911#endif 1921#endif
1912 1922
@@ -1915,24 +1925,24 @@ reset_sys_modes (tty_out)
1915#ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */ 1925#ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
1916 if (interrupt_input) 1926 if (interrupt_input)
1917 { 1927 {
1918 reset_sigio (fileno (TTY_INPUT (tty_out))); 1928 reset_sigio (fileno (tty_out->input));
1919 fcntl (fileno (TTY_INPUT (tty_out)), F_SETOWN, 1929 fcntl (fileno (tty_out->input), F_SETOWN,
1920 old_fcntl_owner[fileno (TTY_INPUT (tty_out))]); 1930 old_fcntl_owner[fileno (tty_out->input)]);
1921 } 1931 }
1922#endif /* F_SETOWN */ 1932#endif /* F_SETOWN */
1923#endif /* F_SETOWN_BUG */ 1933#endif /* F_SETOWN_BUG */
1924#ifdef O_NDELAY 1934#ifdef O_NDELAY
1925 fcntl (fileno (TTY_INPUT (tty_out)), F_SETFL, 1935 fcntl (fileno (tty_out->input), F_SETFL,
1926 fcntl (fileno (TTY_INPUT (tty_out)), F_GETFL, 0) & ~O_NDELAY); 1936 fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY);
1927#endif 1937#endif
1928#endif /* F_SETFL */ 1938#endif /* F_SETFL */
1929#ifdef BSD4_1 1939#ifdef BSD4_1
1930 if (interrupt_input) 1940 if (interrupt_input)
1931 reset_sigio (fileno (TTY_INPUT (tty_out))); 1941 reset_sigio (fileno (tty_out->input));
1932#endif /* BSD4_1 */ 1942#endif /* BSD4_1 */
1933 1943
1934 if (tty_out->old_tty) 1944 if (tty_out->old_tty)
1935 while (EMACS_SET_TTY (fileno (TTY_INPUT (tty_out)), 1945 while (EMACS_SET_TTY (fileno (tty_out->input),
1936 tty_out->old_tty, 0) < 0 && errno == EINTR) 1946 tty_out->old_tty, 0) < 0 && errno == EINTR)
1937 ; 1947 ;
1938 1948
@@ -1952,7 +1962,7 @@ reset_sys_modes (tty_out)
1952#endif 1962#endif
1953 1963
1954#ifdef BSD_PGRPS 1964#ifdef BSD_PGRPS
1955 widen_foreground_group (fileno (TTY_INPUT (tty_out))); 1965 widen_foreground_group (fileno (tty_out->input));
1956#endif 1966#endif
1957} 1967}
1958 1968
@@ -2017,9 +2027,9 @@ init_vms_input ()
2017{ 2027{
2018 int status; 2028 int status;
2019 2029
2020 if (fileno (TTY_INPUT (CURTTY())) == 0) 2030 if (fileno (CURTTY ()->input)) == 0)
2021 { 2031 {
2022 status = SYS$ASSIGN (&input_dsc, &fileno (TTY_INPUT (CURTTY())), 0, 0); 2032 status = SYS$ASSIGN (&input_dsc, &fileno (CURTTY ()->input)), 0, 0);
2023 if (! (status & 1)) 2033 if (! (status & 1))
2024 LIB$STOP (status); 2034 LIB$STOP (status);
2025 } 2035 }
@@ -2030,7 +2040,7 @@ init_vms_input ()
2030void 2040void
2031stop_vms_input () 2041stop_vms_input ()
2032{ 2042{
2033 return SYS$DASSGN (fileno (TTY_INPUT (CURTTY()))); 2043 return SYS$DASSGN (fileno (CURTTY ()->input)));
2034} 2044}
2035 2045
2036short input_buffer; 2046short input_buffer;
@@ -2046,7 +2056,7 @@ queue_kbd_input ()
2046 2056
2047 waiting_for_ast = 0; 2057 waiting_for_ast = 0;
2048 stop_input = 0; 2058 stop_input = 0;
2049 status = SYS$QIO (0, fileno (TTY_INPUT (CURTTY())), IO$_READVBLK, 2059 status = SYS$QIO (0, fileno (CURTTY()->input), IO$_READVBLK,
2050 &input_iosb, kbd_input_ast, 1, 2060 &input_iosb, kbd_input_ast, 1,
2051 &input_buffer, 1, 0, terminator_mask, 0, 0); 2061 &input_buffer, 1, 0, terminator_mask, 0, 0);
2052} 2062}
@@ -2163,7 +2173,7 @@ end_kbd_input ()
2163#endif 2173#endif
2164 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */ 2174 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
2165 { 2175 {
2166 SYS$CANCEL (fileno (TTY_INPUT (CURTTY()))); 2176 SYS$CANCEL (fileno (CURTTY()->input));
2167 return; 2177 return;
2168 } 2178 }
2169 2179
@@ -2172,7 +2182,7 @@ end_kbd_input ()
2172 SYS$CLREF (input_ef); 2182 SYS$CLREF (input_ef);
2173 waiting_for_ast = 1; 2183 waiting_for_ast = 1;
2174 stop_input = 1; 2184 stop_input = 1;
2175 SYS$CANCEL (fileno (TTY_INPUT (CURTTY()))); 2185 SYS$CANCEL (fileno (CURTTY()->input));
2176 SYS$SETAST (1); 2186 SYS$SETAST (1);
2177 SYS$WAITFR (input_ef); 2187 SYS$WAITFR (input_ef);
2178 waiting_for_ast = 0; 2188 waiting_for_ast = 0;
diff --git a/src/term.c b/src/term.c
index e3b176c51ea..785f2a3bb33 100644
--- a/src/term.c
+++ b/src/term.c
@@ -106,9 +106,15 @@ void delete_tty_output P_ ((struct frame *));
106 106
107Lisp_Object Vring_bell_function; 107Lisp_Object Vring_bell_function;
108 108
109/* Functions to call after a tty was deleted. */ 109/* Functions to call after deleting a tty. */
110Lisp_Object Vdelete_tty_after_functions; 110Lisp_Object Vdelete_tty_after_functions;
111 111
112/* Functions to call after suspending a tty. */
113Lisp_Object Vsuspend_tty_functions;
114
115/* Functions to call after resuming a tty. */
116Lisp_Object Vresume_tty_functions;
117
112/* Chain of all displays currently in use. */ 118/* Chain of all displays currently in use. */
113struct display *display_list; 119struct display *display_list;
114 120
@@ -231,10 +237,13 @@ tty_set_terminal_modes (struct display *display)
231{ 237{
232 struct tty_display_info *tty = display->display_info.tty; 238 struct tty_display_info *tty = display->display_info.tty;
233 239
234 OUTPUT_IF (tty, tty->TS_termcap_modes); 240 if (tty->output)
235 OUTPUT_IF (tty, tty->TS_cursor_visible); 241 {
236 OUTPUT_IF (tty, tty->TS_keypad_mode); 242 OUTPUT_IF (tty, tty->TS_termcap_modes);
237 losecursor (tty); 243 OUTPUT_IF (tty, tty->TS_cursor_visible);
244 OUTPUT_IF (tty, tty->TS_keypad_mode);
245 losecursor (tty);
246 }
238} 247}
239 248
240/* Reset termcap modes before exiting Emacs. */ 249/* Reset termcap modes before exiting Emacs. */
@@ -243,16 +252,19 @@ void
243tty_reset_terminal_modes (struct display *display) 252tty_reset_terminal_modes (struct display *display)
244{ 253{
245 struct tty_display_info *tty = display->display_info.tty; 254 struct tty_display_info *tty = display->display_info.tty;
246 255
247 turn_off_highlight (tty); 256 if (tty->output)
248 turn_off_insert (tty); 257 {
249 OUTPUT_IF (tty, tty->TS_end_keypad_mode); 258 turn_off_highlight (tty);
250 OUTPUT_IF (tty, tty->TS_cursor_normal); 259 turn_off_insert (tty);
251 OUTPUT_IF (tty, tty->TS_end_termcap_modes); 260 OUTPUT_IF (tty, tty->TS_end_keypad_mode);
252 OUTPUT_IF (tty, tty->TS_orig_pair); 261 OUTPUT_IF (tty, tty->TS_cursor_normal);
253 /* Output raw CR so kernel can track the cursor hpos. */ 262 OUTPUT_IF (tty, tty->TS_end_termcap_modes);
254 current_tty = tty; 263 OUTPUT_IF (tty, tty->TS_orig_pair);
255 cmputc ('\r'); 264 /* Output raw CR so kernel can track the cursor hpos. */
265 current_tty = tty;
266 cmputc ('\r');
267 }
256} 268}
257 269
258void 270void
@@ -619,9 +631,9 @@ tty_clear_end_of_line (int first_unused_hpos)
619 631
620 for (i = curX (tty); i < first_unused_hpos; i++) 632 for (i = curX (tty); i < first_unused_hpos; i++)
621 { 633 {
622 if (TTY_TERMSCRIPT (tty)) 634 if (tty->termscript)
623 fputc (' ', TTY_TERMSCRIPT (tty)); 635 fputc (' ', tty->termscript);
624 fputc (' ', TTY_OUTPUT (tty)); 636 fputc (' ', tty->output);
625 } 637 }
626 cmplus (tty, first_unused_hpos - curX (tty)); 638 cmplus (tty, first_unused_hpos - curX (tty));
627 } 639 }
@@ -807,12 +819,12 @@ tty_write_glyphs (struct glyph *string, int len)
807 if (produced > 0) 819 if (produced > 0)
808 { 820 {
809 fwrite (conversion_buffer, 1, produced, 821 fwrite (conversion_buffer, 1, produced,
810 TTY_OUTPUT (tty)); 822 tty->output);
811 if (ferror (TTY_OUTPUT (tty))) 823 if (ferror (tty->output))
812 clearerr (TTY_OUTPUT (tty)); 824 clearerr (tty->output);
813 if (TTY_TERMSCRIPT (tty)) 825 if (tty->termscript)
814 fwrite (conversion_buffer, 1, produced, 826 fwrite (conversion_buffer, 1, produced,
815 TTY_TERMSCRIPT (tty)); 827 tty->termscript);
816 } 828 }
817 len -= consumed; 829 len -= consumed;
818 n -= consumed; 830 n -= consumed;
@@ -833,12 +845,12 @@ tty_write_glyphs (struct glyph *string, int len)
833 if (terminal_coding.produced > 0) 845 if (terminal_coding.produced > 0)
834 { 846 {
835 fwrite (conversion_buffer, 1, terminal_coding.produced, 847 fwrite (conversion_buffer, 1, terminal_coding.produced,
836 TTY_OUTPUT (tty)); 848 tty->output);
837 if (ferror (TTY_OUTPUT (tty))) 849 if (ferror (tty->output))
838 clearerr (TTY_OUTPUT (tty)); 850 clearerr (tty->output);
839 if (TTY_TERMSCRIPT (tty)) 851 if (tty->termscript)
840 fwrite (conversion_buffer, 1, terminal_coding.produced, 852 fwrite (conversion_buffer, 1, terminal_coding.produced,
841 TTY_TERMSCRIPT (tty)); 853 tty->termscript);
842 } 854 }
843 } 855 }
844 856
@@ -927,12 +939,12 @@ tty_insert_glyphs (struct glyph *start, int len)
927 if (produced > 0) 939 if (produced > 0)
928 { 940 {
929 fwrite (conversion_buffer, 1, produced, 941 fwrite (conversion_buffer, 1, produced,
930 TTY_OUTPUT (tty)); 942 tty->output);
931 if (ferror (TTY_OUTPUT (tty))) 943 if (ferror (tty->output))
932 clearerr (TTY_OUTPUT (tty)); 944 clearerr (tty->output);
933 if (TTY_TERMSCRIPT (tty)) 945 if (tty->termscript)
934 fwrite (conversion_buffer, 1, produced, 946 fwrite (conversion_buffer, 1, produced,
935 TTY_TERMSCRIPT (tty)); 947 tty->termscript);
936 } 948 }
937 949
938 OUTPUT1_IF (tty, tty->TS_pad_inserted_char); 950 OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
@@ -2240,7 +2252,11 @@ term_init (char *name, char *terminal_type, int must_succeed)
2240 2252
2241 display = get_named_tty_display (name); 2253 display = get_named_tty_display (name);
2242 if (display) 2254 if (display)
2243 return display; /* We have already opened a display there. */ 2255 {
2256 if (! display->display_info.tty->input)
2257 error ("%s already has a suspended frame on it, can't open it twice", name);
2258 return display;
2259 }
2244 2260
2245 display = create_display (); 2261 display = create_display ();
2246 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info)); 2262 tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
@@ -2550,7 +2566,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
2550 /* Get frame size from system, or else from termcap. */ 2566 /* Get frame size from system, or else from termcap. */
2551 { 2567 {
2552 int height, width; 2568 int height, width;
2553 get_tty_size (fileno (TTY_INPUT (tty)), &width, &height); 2569 get_tty_size (fileno (tty->input), &width, &height);
2554 FrameCols (tty) = width; 2570 FrameCols (tty) = width;
2555 FrameRows (tty) = height; 2571 FrameRows (tty) = height;
2556 } 2572 }
@@ -2735,7 +2751,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
2735 && tty->TS_end_standout_mode 2751 && tty->TS_end_standout_mode
2736 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode)); 2752 && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
2737 2753
2738 UseTabs (tty) = tabs_safe_p (fileno (TTY_INPUT (tty))) && TabWidth (tty) == 8; 2754 UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
2739 2755
2740 display->scroll_region_ok 2756 display->scroll_region_ok
2741 = (tty->Wcm->cm_abs 2757 = (tty->Wcm->cm_abs
@@ -2754,7 +2770,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
2754 2770
2755 display->fast_clear_end_of_line = tty->TS_clr_line != 0; 2771 display->fast_clear_end_of_line = tty->TS_clr_line != 0;
2756 2772
2757 init_baud_rate (fileno (TTY_INPUT (tty))); 2773 init_baud_rate (fileno (tty->input));
2758 2774
2759#ifdef AIXHFT 2775#ifdef AIXHFT
2760 /* The HFT system on AIX doesn't optimize for scrolling, so it's 2776 /* The HFT system on AIX doesn't optimize for scrolling, so it's
@@ -3067,6 +3083,134 @@ delete_display (struct display *dev)
3067 xfree (dev); 3083 xfree (dev);
3068} 3084}
3069 3085
3086
3087
3088DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
3089 doc: /* Suspend the terminal device TTY.
3090The terminal is restored to its default state, and Emacs closes all
3091access to the terminal device. Frames that use the device are not
3092deleted, but input is not read from them and if they change, their
3093display is not updated.
3094
3095TTY may a string (a device name), a frame, or nil for the display
3096device of the currently selected frame.
3097
3098This function runs `suspend-tty-functions' after suspending the
3099device. The functions are run with one arg, the name of the terminal
3100device.
3101
3102`suspend-tty' does nothing if it is called on an already suspended
3103device.
3104
3105A suspended terminal device may be resumed by calling `resume-tty' on
3106it. */)
3107 (tty)
3108 Lisp_Object tty;
3109{
3110 struct display *d = get_tty_display (tty);
3111 FILE *f;
3112
3113 if (!d)
3114 error ("Unknown tty device");
3115
3116 f = d->display_info.tty->input;
3117
3118 if (f)
3119 {
3120 reset_sys_modes (d->display_info.tty);
3121
3122 delete_keyboard_wait_descriptor (fileno (f));
3123
3124 fclose (f);
3125 if (f != d->display_info.tty->output)
3126 fclose (d->display_info.tty->output);
3127
3128 d->display_info.tty->input = 0;
3129 d->display_info.tty->output = 0;
3130
3131 if (FRAMEP (d->display_info.tty->top_frame))
3132 FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 0);
3133
3134 /* Run `suspend-tty-functions'. */
3135 if (!NILP (Vrun_hooks))
3136 {
3137 Lisp_Object args[2];
3138 args[0] = intern ("suspend-tty-functions");
3139 if (d->display_info.tty->name)
3140 {
3141 args[1] = build_string (d->display_info.tty->name);
3142 }
3143 else
3144 args[1] = Qnil;
3145 Frun_hook_with_args (2, args);
3146 }
3147 }
3148
3149 return Qnil;
3150}
3151
3152
3153DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
3154 doc: /* Resume the previously suspended terminal device TTY.
3155The terminal is opened and reinitialized. Frames that used the
3156suspended device are revived.
3157
3158This function runs `resume-tty-functions' after resuming the device.
3159The functions are run with one arg, the name of the terminal device.
3160
3161`resume-tty' does nothing if it is called on a device that is not
3162suspended.
3163
3164TTY may a string (a device name), a frame, or nil for the display
3165device of the currently selected frame. */)
3166 (tty)
3167 Lisp_Object tty;
3168{
3169 struct display *d = get_tty_display (tty);
3170 int fd;
3171
3172 if (!d)
3173 error ("Unknown tty device");
3174
3175 if (!d->display_info.tty->input)
3176 {
3177 fd = emacs_open (d->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
3178
3179#ifdef TIOCNOTTY
3180 /* Drop our controlling tty if it is the same device. */
3181 if (ioctl (fd, TIOCNOTTY, 0) != -1)
3182 {
3183 no_controlling_tty = 1;
3184 }
3185#endif
3186
3187 d->display_info.tty->output = fdopen (fd, "w+");
3188 d->display_info.tty->input = d->display_info.tty->output;
3189
3190 add_keyboard_wait_descriptor (fd);
3191
3192 if (FRAMEP (d->display_info.tty->top_frame))
3193 FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 1);
3194
3195 init_sys_modes (d->display_info.tty);
3196
3197 /* Run `suspend-tty-functions'. */
3198 if (!NILP (Vrun_hooks))
3199 {
3200 Lisp_Object args[2];
3201 args[0] = intern ("resume-tty-functions");
3202 if (d->display_info.tty->name)
3203 {
3204 args[1] = build_string (d->display_info.tty->name);
3205 }
3206 else
3207 args[1] = Qnil;
3208 Frun_hook_with_args (2, args);
3209 }
3210 }
3211
3212 return Qnil;
3213}
3070 3214
3071 3215
3072void 3216void
@@ -3092,6 +3236,20 @@ The functions are run with one argument, the name of the tty to be deleted.
3092See `delete-tty'. */); 3236See `delete-tty'. */);
3093 Vdelete_tty_after_functions = Qnil; 3237 Vdelete_tty_after_functions = Qnil;
3094 3238
3239
3240 DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
3241 doc: /* Functions to be run after suspending a tty.
3242The functions are run with one argument, the name of the tty to be suspended.
3243See `suspend-tty'. */);
3244 Vsuspend_tty_functions = Qnil;
3245
3246
3247 DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
3248 doc: /* Functions to be run after resuming a tty.
3249The functions are run with one argument, the name of the tty that was revived.
3250See `resume-tty'. */);
3251 Vresume_tty_functions = Qnil;
3252
3095 Qframe_tty_name = intern ("frame-tty-name"); 3253 Qframe_tty_name = intern ("frame-tty-name");
3096 staticpro (&Qframe_tty_name); 3254 staticpro (&Qframe_tty_name);
3097 3255
@@ -3103,6 +3261,8 @@ See `delete-tty'. */);
3103 defsubr (&Sframe_tty_name); 3261 defsubr (&Sframe_tty_name);
3104 defsubr (&Sframe_tty_type); 3262 defsubr (&Sframe_tty_type);
3105 defsubr (&Sdelete_tty); 3263 defsubr (&Sdelete_tty);
3264 defsubr (&Ssuspend_tty);
3265 defsubr (&Sresume_tty);
3106 3266
3107 Fprovide (intern ("multi-tty"), Qnil); 3267 Fprovide (intern ("multi-tty"), Qnil);
3108 3268
diff --git a/src/termchar.h b/src/termchar.h
index fbf91f2458f..3053061c1b7 100644
--- a/src/termchar.h
+++ b/src/termchar.h
@@ -42,8 +42,10 @@ struct tty_display_info
42 42
43 /* Input/output */ 43 /* Input/output */
44 44
45 FILE *input; /* The stream to be used for terminal input. */ 45 FILE *input; /* The stream to be used for terminal input.
46 FILE *output; /* The stream to be used for terminal output. */ 46 NULL if the terminal is suspended. */
47 FILE *output; /* The stream to be used for terminal output.
48 NULL if the terminal is suspended. */
47 49
48 FILE *termscript; /* If nonzero, send all terminal output 50 FILE *termscript; /* If nonzero, send all terminal output
49 characters to this stream also. */ 51 characters to this stream also. */
@@ -200,9 +202,5 @@ extern struct tty_display_info *tty_list;
200 202
201#define CURTTY() FRAME_TTY (SELECTED_FRAME()) 203#define CURTTY() FRAME_TTY (SELECTED_FRAME())
202 204
203#define TTY_INPUT(t) ((t)->input)
204#define TTY_OUTPUT(t) ((t)->output)
205#define TTY_TERMSCRIPT(t) ((t)->termscript)
206
207/* arch-tag: bf9f0d49-842b-42fb-9348-ec8759b27193 205/* arch-tag: bf9f0d49-842b-42fb-9348-ec8759b27193
208 (do not change this comment) */ 206 (do not change this comment) */
diff --git a/src/termhooks.h b/src/termhooks.h
index c79e77379b1..6b2b0d07867 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -513,7 +513,6 @@ struct display
513 frames on the display when it calls this hook, so infinite 513 frames on the display when it calls this hook, so infinite
514 recursion is prevented. */ 514 recursion is prevented. */
515 void (*delete_display_hook) P_ ((struct display *)); 515 void (*delete_display_hook) P_ ((struct display *));
516
517}; 516};
518 517
519 518