1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-24 19:03:29 +00:00

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
This commit is contained in:
Karoly Lorentey 2004-02-28 01:23:39 +00:00
parent 2fc0cf2aef
commit 0b0d3e0bce
13 changed files with 733 additions and 309 deletions

View File

@ -200,22 +200,50 @@ THINGS TO DO
argument-handling is done in Lisp, so this should be quite easy to
implement.
** Very strange bug: visible-bell does not work on secondary
terminals. This might be something xterm (konsole) specific.
** Make `struct display' accessible to Lisp programs. Accessor functions:
** Find out the best way to support suspending Emacs with multiple
ttys. My guess: disable it on the controlling tty, but from other
ttys pass it on to emacsclient somehow. (It is (I hope) trivial to
extend emacsclient to handle suspend/resume. A `kill -STOP' almost
works right now.)
(displayp OBJECT): Returns t if OBJECT is a display.
** Clean up the frame-local variable system. I think it's ugly and
error-prone. But maybe I just haven't yet fully understood it.
(selected-display): Returns the display object of the selected frame.
(frame-display FRAME): Returns the display object of FRAME.
(display-frames DISPLAY): Returns a list of frames on DISPLAY.
(display-type DISPLAY): Returns the type of DISPLAY, as a
symbol. (See `framep'.)
(display-device DISPLAY): Returns the name of the device that
DISPLAY uses, as a string. (E.g: "/dev/pts/16", or
":0.0")
See next issue why this is necessary.
** The following needs to be supported:
$ emacsclient -t
C-z
$ bg
$ emacsclient -t
(This fails now.)
The cleanest way to solve this is to allow multiple displays on the
same terminal device; each new emacsclient process should create
its own display. As displays are currently identified by their
device names, this is not possible until struct display becomes
accessible as a Lisp-level object.
** Add an elaborate mechanism for display-local variables. (There are
already a few of these; search for `terminal-local' in the Elisp
manual.)
** Very strange bug: visible-bell does not work on secondary
terminals in xterm and konsole. The screen does flicker a bit,
but it's so quick it isn't noticable.
** Clean up the frame-local variable system. I think it's ugly and
error-prone. But maybe I just haven't yet fully understood it.
** Move baud_rate to struct display.
** Implement support for starting an interactive Emacs session without
@ -667,4 +695,15 @@ DIARY OF CHANGES
complaints seem to be caused by bugs in term.el; they are not
related to multi-tty.)
-- Find out the best way to support suspending Emacs with multiple
ttys. My guess: disable it on the controlling tty, but from other
ttys pass it on to emacsclient somehow. (It is (I hope) trivial to
extend emacsclient to handle suspend/resume. A `kill -STOP' almost
works right now.)
(Done. I needed to play with signal handling and the server
protocol a bit to make emacsclient behave as a normal UNIX program
wrt foreground/background process groups.)
;;; arch-tag: 8da1619e-2e79-41a8-9ac9-a0485daad17d

View File

@ -114,7 +114,7 @@ decode_options (argc, argv)
display = getenv ("DISPLAY");
if (display && strlen (display) == 0)
display = NULL;
if (display)
window_system = 1;
else
@ -169,7 +169,7 @@ decode_options (argc, argv)
window_system = 0;
tty = 0;
break;
case 'H':
print_help_and_exit ();
break;
@ -212,19 +212,21 @@ Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
exit (0);
}
/* In NAME, insert a & before each &, each space, each newline, and
/* In STR, insert a & before each &, each space, each newline, and
any initial -. Change spaces to underscores, too, so that the
return value never contains a space. */
return value never contains a space.
Does not change the string. Outputs the result to STREAM. */
void
quote_file_name (name, stream)
char *name;
quote_argument (str, stream)
char *str;
FILE *stream;
{
char *copy = (char *) malloc (strlen (name) * 2 + 1);
char *copy = (char *) malloc (strlen (str) * 2 + 1);
char *p, *q;
p = name;
p = str;
q = copy;
while (*p)
{
@ -242,7 +244,7 @@ quote_file_name (name, stream)
}
else
{
if (*p == '&' || (*p == '-' && p == name))
if (*p == '&' || (*p == '-' && p == str))
*q++ = '&';
*q++ = *p++;
}
@ -254,6 +256,41 @@ quote_file_name (name, stream)
free (copy);
}
/* The inverse of quote_argument. Removes quoting in string STR by
modifying the string in place. Returns STR. */
char *
unquote_argument (str)
char *str;
{
char *p, *q;
if (! str)
return str;
p = str;
q = str;
while (*p)
{
if (*p == '&')
{
p++;
if (*p == '&')
*p = '&';
else if (*p == '_')
*p = ' ';
else if (*p == 'n')
*p = '\n';
else if (*p == '-')
*p = '-';
}
*q++ = *p++;
}
*q = 0;
return str;
}
/* Like malloc but get fatal error if memory is exhausted. */
long *
@ -288,8 +325,12 @@ fail (void)
}
}
/* The process id of Emacs. */
int emacs_pid;
/* File handles for communicating with Emacs. */
FILE *out, *in;
/* A signal handler that passes the signal to the Emacs process.
Useful for SIGWINCH. */
@ -305,8 +346,62 @@ pass_signal_to_emacs (int signalnum)
errno = old_errno;
}
/* Signal handler for SIGCONT; notify the Emacs process that it can
now resume our tty frame. */
SIGTYPE
handle_sigcont (int signalnum)
{
int old_errno = errno;
if (tcgetpgrp (1) == getpgrp ())
{
/* We are in the foreground. */
fprintf (out, "-resume \n");
fflush (out);
fsync (fileno (out));
}
else
{
/* We are in the background; cancel the continue. */
kill (getpid (), SIGSTOP);
}
errno = old_errno;
}
/* Signal handler for SIGTSTP; notify the Emacs process that we are
going to sleep. Normally the suspend is initiated by Emacs via
server-handle-suspend-tty, but if the server gets out of sync with
reality, we may get a SIGTSTP on C-z. Handling this signal and
notifying Emacs about it should get things under control again. */
SIGTYPE
handle_sigtstp (int signalnum)
{
int old_errno = errno;
sigset_t set;
if (out)
{
fprintf (out, "-suspend \n");
fflush (out);
fsync (fileno (out));
}
/* Unblock this signal and call the default handler by temprarily
changing the handler and resignalling. */
sigprocmask (SIG_BLOCK, NULL, &set);
sigdelset (&set, signalnum);
signal (signalnum, SIG_DFL);
kill (getpid (), signalnum);
sigprocmask (SIG_SETMASK, &set, NULL); /* Let's the above signal through. */
signal (signalnum, handle_sigtstp);
errno = old_errno;
}
/* Set up signal handlers before opening a frame on the current tty. */
void
init_signals (void)
{
@ -320,6 +415,10 @@ init_signals (void)
signal (SIGINT, pass_signal_to_emacs);
signal (SIGQUIT, pass_signal_to_emacs);
#endif
signal (SIGCONT, handle_sigcont);
signal (SIGTSTP, handle_sigtstp);
signal (SIGTTOU, handle_sigtstp);
}
@ -378,7 +477,7 @@ strprefix (char *prefix, char *string)
if (!string)
return 0;
for (i = 0; prefix[i]; i++)
if (!string[i] || string[i] != prefix[i])
return 0;
@ -391,7 +490,6 @@ main (argc, argv)
char **argv;
{
int s, i, needlf = 0;
FILE *out, *in;
struct sockaddr_un server;
char *cwd, *str;
char string[BUFSIZ];
@ -427,9 +525,9 @@ main (argc, argv)
int sock_status = 0;
int default_sock = !socket_name;
int saved_errno = 0;
char *server_name = "server";
if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
{ /* socket_name is a file name component. */
server_name = socket_name;
@ -571,17 +669,14 @@ To start the server in Emacs, type \"M-x server-start\".\n",
/* First of all, send our version number for verification. */
fprintf (out, "-version %s ", VERSION);
if (nowait)
fprintf (out, "-nowait ");
if (eval)
fprintf (out, "-eval ");
if (display)
{
fprintf (out, "-display ");
quote_file_name (display, out);
quote_argument (display, out);
fprintf (out, " ");
}
@ -589,7 +684,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
{
char *tty_name = ttyname (fileno (stdin));
char *type = getenv ("TERM");
if (! tty_name)
{
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",
" is not supported\n", progname);
fail ();
}
init_signals ();
fprintf (out, "-tty ");
quote_file_name (tty_name, out);
quote_argument (tty_name, out);
fprintf (out, " ");
quote_file_name (type, out);
quote_argument (type, out);
fprintf (out, " ");
}
if (window_system)
fprintf (out, "-window-system ");
if ((argc - optind > 0))
{
for (i = optind; i < argc; i++)
{
int relative = 0;
if (eval)
; /* Don't prepend any cwd or anything like that. */
else if (*argv[i] == '+')
{
{
/* Don't prepend any cwd or anything like that. */
fprintf (out, "-eval ");
quote_argument (argv[i], out);
fprintf (out, " ");
continue;
}
if (*argv[i] == '+')
{
char *p = argv[i] + 1;
while (isdigit ((unsigned char) *p) || *p == ':') p++;
if (*p != 0)
{
quote_file_name (cwd, out);
fprintf (out, "/");
}
}
else if (*argv[i] != '/')
{
quote_file_name (cwd, out);
fprintf (out, "/");
}
if (*p == 0)
{
fprintf (out, "-position ");
quote_argument (argv[i], out);
fprintf (out, " ");
continue;
}
else
relative = 1;
}
else if (*argv[i] != '/')
relative = 1;
quote_file_name (argv[i], out);
fprintf (out, " ");
}
fprintf (out, "-file ");
if (relative)
{
quote_argument (cwd, out);
fprintf (out, "/");
}
quote_argument (argv[i], out);
fprintf (out, " ");
}
}
else
{
@ -655,14 +766,19 @@ To start the server in Emacs, type \"M-x server-start\".\n",
{
while ((str = fgets (string, BUFSIZ, stdin)))
{
quote_file_name (str, out);
if (eval)
fprintf (out, "-eval ");
else
fprintf (out, "-file ");
quote_argument (str, out);
}
fprintf (out, " ");
}
}
fprintf (out, "\n");
fflush (out);
fsync (fileno (out));
/* Maybe wait for an answer. */
if (nowait)
@ -676,44 +792,49 @@ To start the server in Emacs, type \"M-x server-start\".\n",
needlf = 2;
}
fflush (stdout);
fsync (1);
/* Now, wait for an answer and print any messages. */
while ((str = fgets (string, BUFSIZ, in)))
{
char *p = str + strlen (str) - 1;
while (p > str && *p == '\n')
*p-- = 0;
if (strprefix ("-good-version ", str))
{
/* OK, we got the green light. */
}
else if (strprefix ("-bad-version ", str))
{
if (str[strlen (str) - 1] == '\n')
str[strlen (str) - 1] = 0;
fprintf (stderr, "%s: Version mismatch: Emacs is %s, but we are %s\n",
argv[0], str + strlen ("-bad-version "), VERSION);
fail ();
}
else if (strprefix ("-emacs-pid ", str))
{
emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
}
else if (strprefix ("-print ", str))
{
if (needlf == 2)
str = unquote_argument (str + strlen ("-print "));
if (needlf)
printf ("\n");
printf ("%s", str + strlen ("-print "));
needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
printf ("%s", str);
needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
}
else if (strprefix ("-error ", str))
{
if (needlf == 2)
str = unquote_argument (str + strlen ("-error "));
if (needlf)
printf ("\n");
printf ("*ERROR*: %s", str + strlen ("-print "));
needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
printf ("*ERROR*: %s", str);
needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
}
else if (strprefix ("-suspend ", str))
{
if (needlf)
printf ("\n");
needlf = 0;
kill (0, SIGSTOP);
}
else
{
if (needlf == 2)
if (needlf)
printf ("\n");
printf ("*ERROR*: Unknown message: %s", str);
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",
if (needlf)
printf ("\n");
fflush (stdout);
fsync (1);
return 0;
}

View File

@ -750,6 +750,22 @@ Otherwise, that variable should be nil."
(iconify-frame)
(make-frame-visible)))
(defun suspend-frame ()
"Do whatever is right to suspend the current frame.
Calls `suspend-emacs' if invoked from the controlling terminal,
`suspend-tty' from a secondary terminal, and
`iconify-or-deiconify-frame' from an X frame."
(interactive)
(let ((type (framep (selected-frame))))
(cond
((eq type 'x) (iconify-or-deiconify-frame))
((eq type t)
(if (frame-tty-name)
(suspend-tty)
(suspend-emacs)))
(t (suspend-emacs)))))
(defun make-frame-names-alist ()
(let* ((current-frame (selected-frame))
(falist
@ -1374,6 +1390,8 @@ Use Custom to set this variable to get the display updated."
(define-key ctl-x-5-map "0" 'delete-frame)
(define-key ctl-x-5-map "o" 'other-frame)
(substitute-key-definition 'suspend-emacs 'suspend-frame global-map)
(provide 'frame)
;;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56

View File

@ -186,7 +186,7 @@ are done with it in the server.")
(with-current-buffer "*server*"
(goto-char (point-max))
(insert (current-time-string)
(if client (format " %s:" client) " ")
(if client (format " %s: " client) " ")
string)
(or (bolp) (newline)))))
@ -227,6 +227,7 @@ are done with it in the server.")
(term (nth 1 entry)))
(when (equal term tty)
(let ((client (assq proc server-clients)))
(server-log (format "server-handle-delete-tty, tty %s" tty) (car client))
(setq server-ttys (delq entry server-ttys))
(delete-process (car client))
(when (assq proc server-clients)
@ -234,6 +235,16 @@ are done with it in the server.")
;; `emacsclient -t -e '(delete-frame)'' correctly.
(setq server-clients (delq client server-clients))))))))
(defun server-handle-suspend-tty (tty)
"Notify the emacsclient process to suspend itself when its tty device is suspended."
(dolist (entry server-ttys)
(let ((proc (nth 0 entry))
(term (nth 1 entry)))
(when (equal term tty)
(let ((process (car (assq proc server-clients))))
(server-log (format "server-handle-suspend-tty, tty %s" tty) process)
(process-send-string process "-suspend \n"))))))
(defun server-handle-delete-frame (frame)
"Delete the client connection when the emacsclient frame is deleted."
(dolist (entry server-frames)
@ -241,6 +252,7 @@ are done with it in the server.")
(f (nth 1 entry)))
(when (equal frame f)
(let ((client (assq proc server-clients)))
(server-log (format "server-handle-delete-frame, frame %s" frame) (car client))
(setq server-frames (delq entry server-frames))
(delete-process (car client))
(when (assq proc server-clients)
@ -278,6 +290,19 @@ are done with it in the server.")
(t " ")))
arg t t))
(defun server-quote-arg (arg)
"In NAME, insert a & before each &, each space, each newline, and -.
Change spaces to underscores, too, so that the return value never
contains a space."
(replace-regexp-in-string
"[-&\n ]" (lambda (s)
(case (aref s 0)
(?& "&&")
(?- "&-")
(?\n "&n")
(?\s "&_")))
arg t t))
(defun server-ensure-safe-dir (dir)
"Make sure DIR is a directory with no race-condition issues.
Creates the directory if necessary and makes sure:
@ -325,6 +350,7 @@ Prefix arg means just kill any existing server communications subprocess."
(server-log (message "Restarting server")))
(letf (((default-file-modes) ?\700))
(add-to-list 'delete-tty-after-functions 'server-handle-delete-tty)
(add-to-list 'suspend-tty-functions 'server-handle-suspend-tty)
(add-to-list 'delete-frame-functions 'server-handle-delete-frame)
(setq server-process
(make-network-process
@ -358,140 +384,182 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
(setq string (concat prev string))
(process-put proc 'previous-string nil)))
(condition-case err
;; If the input is multiple lines,
;; process each line individually.
(while (string-match "\n" string)
(let ((request (substring string 0 (match-beginning 0)))
(coding-system (and default-enable-multibyte-characters
(or file-name-coding-system
default-file-name-coding-system)))
client nowait eval newframe display version-checked
registered ; t if the client is already added to server-clients.
(files nil)
(lineno 1)
(columnno 0))
;; Remove this line from STRING.
(setq string (substring string (match-end 0)))
(setq client (cons proc nil))
(while (string-match "[^ ]* " request)
(let ((arg (substring request (match-beginning 0) (1- (match-end 0)))))
(setq request (substring request (match-end 0)))
(cond
;; Check version numbers.
((and (equal "-version" arg) (string-match "\\([0-9.]+\\) " request))
(let* ((client-version (match-string 1 request))
(truncated-emacs-version (substring emacs-version 0 (length client-version))))
(setq request (substring request (match-end 0)))
(if (equal client-version truncated-emacs-version)
(progn
(process-send-string proc "-good-version \n")
(setq version-checked t))
(error (concat "Version mismatch: Emacs is " truncated-emacs-version ", emacsclient is " client-version)))))
(progn
;; If the input is multiple lines,
;; process each line individually.
(while (string-match "\n" string)
(let ((request (substring string 0 (match-beginning 0)))
(coding-system (and default-enable-multibyte-characters
(or file-name-coding-system
default-file-name-coding-system)))
client nowait newframe display version-checked
dontkill ; t if the client should not be killed.
registered ; t if the client is already added to server-clients.
(files nil)
(lineno 1)
(columnno 0))
;; Remove this line from STRING.
(setq string (substring string (match-end 0)))
(setq client (cons proc nil))
(while (string-match "[^ ]* " request)
(let ((arg (substring request (match-beginning 0) (1- (match-end 0)))))
(setq request (substring request (match-end 0)))
(cond
;; Check version numbers.
((and (equal "-version" arg) (string-match "\\([0-9.]+\\) " request))
(let* ((client-version (match-string 1 request))
(truncated-emacs-version (substring emacs-version 0 (length client-version))))
(setq request (substring request (match-end 0)))
(if (equal client-version truncated-emacs-version)
(progn
(process-send-string proc "-good-version \n")
(setq version-checked t))
(error (concat "Version mismatch: Emacs is " truncated-emacs-version ", emacsclient is " client-version)))))
((equal "-nowait" arg) (setq nowait t))
((equal "-eval" arg) (setq eval t))
((equal "-nowait" arg) (setq nowait t))
((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
(setq display (match-string 1 request)
request (substring request (match-end 0))))
((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
(setq display (match-string 1 request)
request (substring request (match-end 0))))
;; Open a new X frame.
((equal "-window-system" arg)
(unless version-checked
(error "Protocol error; make sure to use the correct version of emacsclient"))
(let ((frame (make-frame-on-display
(or display
(frame-parameter nil 'display)
(getenv "DISPLAY")
(error "Please specify display")))))
(push (list proc frame) server-frames)
(select-frame frame)
;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
(push client server-clients)
(setq registered t
newframe t)))
;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
(let ((tty (server-unquote-arg (match-string 1 request)))
(type (server-unquote-arg (match-string 2 request))))
(setq request (substring request (match-end 0)))
;; Open a new X frame.
((equal "-window-system" arg)
(unless version-checked
(error "Protocol error; make sure to use the correct version of emacsclient"))
(let ((frame (make-frame-on-tty tty type)))
(push (list (car client) (frame-tty-name frame)) server-ttys)
(process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n"))
(let ((frame (make-frame-on-display
(or display
(frame-parameter nil 'display)
(getenv "DISPLAY")
(error "Please specify display")))))
(push (list proc frame) server-frames)
(select-frame frame)
;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right.
;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
(push client server-clients)
(setq registered t
newframe t))))
newframe t
dontkill t)))
;; ARG is a line number option.
((string-match "\\`\\+[0-9]+\\'" arg)
(setq lineno (string-to-int (substring arg 1))))
;; Resume a suspended tty frame.
((equal "-resume" arg)
(let ((tty (cadr (assq (car client) server-ttys))))
(setq dontkill t)
(when tty (resume-tty tty))))
;; ARG is line number:column option.
((string-match "\\`\\+\\([0-9]+\\):\\([0-9]+\\)\\'" arg)
(setq lineno (string-to-int (match-string 1 arg))
columnno (string-to-int (match-string 2 arg))))
;; Suspend the client's frame. (In case we get out of
;; sync, and a C-z sends a SIGTSTP to emacsclient.)
((equal "-suspend" arg)
(let ((tty (cadr (assq (car client) server-ttys))))
(setq dontkill t)
(when tty (suspend-tty tty))))
;; ARG is a filename or a Lisp expression.
(t
;; Undo the quoting that emacsclient does
;; for certain special characters.
(setq arg (server-unquote-arg arg))
;; Now decode the file name if necessary.
(if coding-system
(setq arg (decode-coding-string arg coding-system)))
(unless version-checked
(error "Protocol error; make sure to use the correct version of emacsclient"))
(if eval
;; ARG is a Lisp expression.
(let ((v (eval (car (read-from-string arg)))))
;; Noop; useful for debugging emacsclient.
((and (equal "-ignore" arg) (string-match "\\([^ ]*\\) " request))
(setq dontkill t
request (substring request (match-end 0))))
;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
(let ((tty (server-unquote-arg (match-string 1 request)))
(type (server-unquote-arg (match-string 2 request))))
(setq request (substring request (match-end 0)))
(unless version-checked
(error "Protocol error; make sure to use the correct version of emacsclient"))
(let ((frame (make-frame-on-tty tty type)))
(push (list (car client) (frame-tty-name frame)) server-ttys)
(process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n"))
(select-frame frame)
;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right.
(push client server-clients)
(setq registered t
dontkill t
newframe t))))
;; ARG is a line number option.
((and (equal "-position" arg) (string-match "\\(\\+[0-9]+\\) " request))
(setq request (substring request (match-end 0))
lineno (string-to-int (substring (match-string 1 request) 1))))
;; ARG is line number:column option.
((and (equal "-position" arg) (string-match "\\+\\([0-9]+\\):\\([0-9]+\\) " request))
(setq request (substring request (match-end 0))
lineno (string-to-int (match-string 1 request))
columnno (string-to-int (match-string 2 request))))
;; ARG is a file to load.
((and (equal "-file" arg) (string-match "\\([^ ]+\\) " request))
(let ((file (server-unquote-arg (match-string 1 request))))
(setq request (substring request (match-end 0)))
(if coding-system
(setq file (decode-coding-string file coding-system)))
(setq file (command-line-normalize-file-name file))
(push (list file lineno columnno) files))
(setq lineno 1
columnno 0))
;; ARG is a Lisp expression.
((and (equal "-eval" arg) (string-match "\\([^ ]+\\) " request))
(let ((expr (server-unquote-arg (match-string 1 request))))
(setq request (substring request (match-end 0)))
(if coding-system
(setq expr (decode-coding-string expr coding-system)))
(let ((v (eval (car (read-from-string expr)))))
(when (and (not newframe) v)
(with-temp-buffer
(let ((standard-output (current-buffer)))
(pp v)
(process-send-string proc "-print ")
(process-send-region proc (point-min) (point-max))))))
;; ARG is a file name.
;; Collapse multiple slashes to single slashes.
(setq arg (command-line-normalize-file-name arg))
(push (list arg lineno columnno) files))
(setq lineno 1)
(setq columnno 0)))))
(process-send-string
proc (server-quote-arg
(buffer-substring-no-properties (point-min)
(point-max))))
(process-send-string proc "\n")))))
(setq lineno 1
columnno 0)))
;; Unknown command.
(t (error "Unknown command: %s" arg)))))
(if (not version-checked)
(error "Protocol error; make sure to use the correct version of emacsclient")
(when files
(run-hooks 'pre-command-hook)
(server-visit-files files client nowait)
(run-hooks 'post-command-hook))
;; CLIENT is now a list (CLIENTNUM BUFFERS...)
(if (and (not newframe) (null (cdr client)))
;; This client is empty; get rid of it immediately.
(progn
(delete-process proc)
(server-log "Close empty client" proc))
;; We visited some buffer for this client.
(or nowait registered (push client server-clients))
(unless (or isearch-mode (minibufferp))
(if (and newframe (null (cdr client)))
(message (substitute-command-keys
"When done with this frame, type \\[delete-frame]"))
(server-switch-buffer (nth 1 client))
(run-hooks 'server-switch-hook)
(unless nowait
(message (substitute-command-keys
"When done with a buffer, type \\[server-edit]"))))))))
;; Delete the client if necessary.
(cond
;; Client requested nowait; return immediately.
(nowait
(delete-process proc)
(server-log "Close nowait client" proc))
;; This client is empty; get rid of it immediately.
((and (not dontkill) (null (cdr client)))
(delete-process proc)
(server-log "Close empty client" proc))
((not registered)
(push client server-clients)))
;; We visited some buffer for this client.
(cond
((or isearch-mode (minibufferp))
nil)
((and newframe (null (cdr client)))
(message (substitute-command-keys
"When done with this frame, type \\[delete-frame]")))
((not (null (cdr client)))
(server-switch-buffer (nth 1 client))
(run-hooks 'server-switch-hook)
(unless nowait
(message (substitute-command-keys
"When done with a buffer, type \\[server-edit]")))))))
;; Save for later any partial line that remains.
(when (> (length string) 0)
(process-put proc 'previous-string string)))
;; condition-case
(error (ignore-errors
(process-send-string
proc (concat "-error " (error-message-string err)))
proc (concat "-error " (server-quote-arg (error-message-string err))))
(setq string "")
(server-log (error-message-string err) proc)
(delete-process proc)))))

View File

@ -2442,11 +2442,7 @@ order until succeed.")
(if res-selection-timeout
(setq x-selection-timeout (string-to-number res-selection-timeout))))
;; XXX This is wrong in general with multi-tty support.
(substitute-key-definition 'suspend-emacs 'iconify-or-deiconify-frame
global-map)
;; XXX This is wrong in general with multi-tty support.
;; Don't let Emacs suspend under X.
(add-hook 'suspend-hook 'x-win-suspend-error)
;; Arrange for the kill and yank functions to set and check the clipboard.

View File

@ -64,9 +64,9 @@ int
cmputc (c)
char c;
{
if (TTY_TERMSCRIPT (current_tty))
putc (c & 0177, TTY_TERMSCRIPT (current_tty));
putc (c & 0177, TTY_OUTPUT (current_tty));
if (current_tty->termscript)
putc (c & 0177, current_tty->termscript);
putc (c & 0177, current_tty->output);
return c;
}
@ -136,12 +136,12 @@ cmcheckmagic (struct tty_display_info *tty)
{
if (!MagicWrap (tty) || curY (tty) >= FrameRows (tty) - 1)
abort ();
if (TTY_TERMSCRIPT (tty))
putc ('\r', TTY_TERMSCRIPT (tty));
putc ('\r', TTY_OUTPUT (tty));
if (TTY_TERMSCRIPT (tty))
putc ('\n', TTY_TERMSCRIPT (tty));
putc ('\n', TTY_OUTPUT (tty));
if (tty->termscript)
putc ('\r', tty->termscript);
putc ('\r', tty->output);
if (tty->termscript)
putc ('\n', tty->termscript);
putc ('\n', tty->output);
curX (tty) = 0;
curY (tty)++;
}

View File

@ -3316,7 +3316,7 @@ DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
clear_current_matrices (f);
update_end (f);
if (FRAME_TERMCAP_P (f))
fflush (TTY_OUTPUT (FRAME_TTY (f)));
fflush (FRAME_TTY (f)->output);
windows_or_buffers_changed++;
/* Mark all windows as inaccurate, so that every window will have
its redisplay done. */
@ -3659,7 +3659,7 @@ direct_output_for_insert (g)
update_end (f);
updated_row = NULL;
if (FRAME_TERMCAP_P (f))
fflush (TTY_OUTPUT (FRAME_TTY (f)));
fflush (FRAME_TTY (f)->output);
TRACE ((stderr, "direct output for insert\n"));
mark_window_display_accurate (it.window, 1);
@ -3751,7 +3751,7 @@ direct_output_forward_char (n)
}
if (FRAME_TERMCAP_P (f))
fflush (TTY_OUTPUT (FRAME_TTY (f)));
fflush (FRAME_TTY (f)->output);
redisplay_performed_directly_p = 1;
return 1;
}
@ -3849,9 +3849,9 @@ update_frame (f, force_p, inhibit_hairy_id_p)
if (FRAME_TERMCAP_P (f))
{
if (TTY_TERMSCRIPT (FRAME_TTY (f)))
fflush (TTY_TERMSCRIPT (FRAME_TTY (f)));
fflush (TTY_OUTPUT (FRAME_TTY (f)));
if (FRAME_TTY (f)->termscript)
fflush (FRAME_TTY (f)->termscript);
fflush (FRAME_TTY (f)->output);
}
/* Check window matrices for lost pointers. */
@ -5133,18 +5133,18 @@ update_frame_1 (f, force_p, inhibit_id_p)
Also flush out if likely to have more than 1k buffered
otherwise. I'm told that some telnet connections get
really screwed by more than 1k output at once. */
int outq = PENDING_OUTPUT_COUNT (TTY_OUTPUT (FRAME_TTY (f)));
int outq = PENDING_OUTPUT_COUNT (FRAME_TTY (f)->output);
if (outq > 900
|| (outq > 20 && ((i - 1) % preempt_count == 0)))
{
fflush (TTY_OUTPUT (FRAME_TTY (f)));
fflush (FRAME_TTY (f)->output);
if (preempt_count == 1)
{
#ifdef EMACS_OUTQSIZE
if (EMACS_OUTQSIZE (0, &outq) < 0)
/* Probably not a tty. Ignore the error and reset
the outq count. */
outq = PENDING_OUTPUT_COUNT (TTY_OUTPUT (FRAME_TTY (f)));
outq = PENDING_OUTPUT_COUNT (FRAME_TTY (f->output));
#endif
outq *= 10;
if (baud_rate <= outq && baud_rate > 0)
@ -5999,7 +5999,7 @@ window_change_signal (signalnum) /* If we don't have an argument, */
if (! tty->term_initted)
continue;
get_tty_size (fileno (TTY_INPUT (tty)), &width, &height);
get_tty_size (fileno (tty->input), &width, &height);
{
Lisp_Object tail, frame;
@ -6211,15 +6211,22 @@ FILE = nil means just close any termscript file currently open. */)
(file)
Lisp_Object file;
{
if (TTY_TERMSCRIPT (CURTTY ()) != 0)
fclose (TTY_TERMSCRIPT (CURTTY ()));
TTY_TERMSCRIPT (CURTTY ()) = 0;
struct tty_display_info *tty;
if (! FRAME_TERMCAP_P (SELECTED_FRAME ()))
error ("Current frame is not on a tty device");
tty = CURTTY ();
if (tty->termscript != 0)
fclose (tty->termscript);
tty->termscript = 0;
if (! NILP (file))
{
file = Fexpand_file_name (file, Qnil);
TTY_TERMSCRIPT (CURTTY ()) = fopen (SDATA (file), "w");
if (TTY_TERMSCRIPT (CURTTY ()) == 0)
tty->termscript = fopen (SDATA (file), "w");
if (tty->termscript == 0)
report_file_error ("Opening termscript", Fcons (file, Qnil));
}
return Qnil;
@ -6233,20 +6240,23 @@ Control characters in STRING will have terminal-dependent effects. */)
(string)
Lisp_Object string;
{
struct tty_display_info *tty;
/* ??? Perhaps we should do something special for multibyte strings here. */
CHECK_STRING (string);
if (! FRAME_TERMCAP_P (SELECTED_FRAME ()))
error ("Current frame is not on a tty device");
tty = CURTTY ();
if (TTY_TERMSCRIPT (CURTTY ()))
if (tty->termscript)
{
fwrite (SDATA (string), 1, SBYTES (string),
TTY_TERMSCRIPT (CURTTY ()));
fflush (TTY_TERMSCRIPT (CURTTY ()));
fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
fflush (tty->termscript);
}
fwrite (SDATA (string), 1, SBYTES (string),
TTY_OUTPUT (CURTTY ()));
fflush (TTY_OUTPUT (CURTTY ()));
fwrite (SDATA (string), 1, SBYTES (string), tty->output);
fflush (tty->output);
return Qnil;
}
@ -6265,7 +6275,7 @@ terminate any keyboard macro currently executing. */)
else
ring_bell ();
if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
fflush (TTY_OUTPUT (CURTTY ()));
fflush (CURTTY ()->output);
}
else
bitch_at_user ();
@ -6283,7 +6293,7 @@ bitch_at_user ()
else
ring_bell ();
if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
fflush (TTY_OUTPUT (CURTTY ()));
fflush (CURTTY ()->output);
}

View File

@ -667,7 +667,8 @@ and the `tty-type' parameter specifies the terminal type. Example:
(make-terminal-frame '((tty . "/dev/pts/5") (tty-type . "xterm")))
Note that changing the size of one terminal frame automatically affects all. */)
Note that changing the size of one terminal frame automatically
affects all frames on the same terminal device. */)
(parms)
Lisp_Object parms;
{
@ -742,7 +743,7 @@ Note that changing the size of one terminal frame automatically affects all. */
{
int width, height;
get_tty_size (fileno (TTY_INPUT (FRAME_TTY (f))), &width, &height);
get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height);
change_frame_size (f, height, width, 0, 0, 0);
}

View File

@ -6704,10 +6704,13 @@ tty_read_avail_input (struct display *display,
if (! tty->term_initted) /* In case we get called during bootstrap. */
return 0;
if (! tty->input)
return 0; /* The terminal is suspended. */
/* Determine how many characters we should *try* to read. */
#ifdef FIONREAD
/* Find out how much input is available. */
if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0)
if (ioctl (fileno (tty->input), FIONREAD, &n_to_read) < 0)
{
if (! noninteractive)
return -2; /* Close this display. */
@ -6722,7 +6725,7 @@ tty_read_avail_input (struct display *display,
#if defined (USG) || defined (DGUX) || defined(CYGWIN)
/* Read some input if available, but don't wait. */
n_to_read = sizeof cbuf;
fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY);
fcntl (fileno (tty->input), F_SETFL, O_NDELAY);
#else
you lose;
#endif
@ -6732,7 +6735,7 @@ tty_read_avail_input (struct display *display,
NREAD is set to the number of chars read. */
do
{
nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read);
nread = emacs_read (fileno (tty->input), cbuf, n_to_read);
/* POSIX infers that processes which are not in the session leader's
process group won't get SIGHUP's at logout time. BSDI adheres to
this part standard and returns -1 from read (0) with errno==EIO
@ -6770,7 +6773,7 @@ tty_read_avail_input (struct display *display,
#ifndef FIONREAD
#if defined (USG) || defined (DGUX) || defined (CYGWIN)
fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0);
fcntl (fileno (tty->input), F_SETFL, 0);
#endif /* USG or DGUX or CYGWIN */
#endif /* no FIONREAD */
@ -10168,7 +10171,7 @@ On such systems, Emacs starts a subshell instead of suspending. */)
call1 (Vrun_hooks, intern ("suspend-hook"));
GCPRO1 (stuffstring);
get_tty_size (fileno (TTY_INPUT (CURTTY ())), &old_width, &old_height);
get_tty_size (fileno (CURTTY ()->input), &old_width, &old_height);
reset_all_sys_modes ();
/* sys_suspend can get an error if it tries to fork a subshell
and the system resources aren't available for that. */
@ -10184,7 +10187,7 @@ On such systems, Emacs starts a subshell instead of suspending. */)
/* Check if terminal/window size has changed.
Note that this is not useful when we are running directly
with a window system; but suspend should be disabled in that case. */
get_tty_size (fileno (TTY_INPUT (CURTTY ())), &width, &height);
get_tty_size (fileno (CURTTY ()->input), &width, &height);
if (width != old_width || height != old_height)
change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0);

View File

@ -274,7 +274,7 @@ discard_tty_input ()
#ifdef VMS
end_kbd_input ();
SYS$QIOW (0, fileno (TTY_INPUT (CURTTY())), IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
SYS$QIOW (0, fileno (CURTTY()->input), IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
&buf.main, 0, 0, terminator_mask, 0, 0);
queue_kbd_input ();
#else /* not VMS */
@ -284,7 +284,8 @@ discard_tty_input ()
for (tty = tty_list; tty; tty = tty->next)
{
int zero = 0;
ioctl (fileno (TTY_INPUT (tty)), TIOCFLUSH, &zero);
if (tty->input)
ioctl (fileno (tty->input), TIOCFLUSH, &zero);
}
}
#else /* not Apollo */
@ -296,8 +297,11 @@ discard_tty_input ()
struct tty_display_info *tty;
for (tty = tty_list; tty; tty = tty->next)
{
EMACS_GET_TTY (fileno (TTY_INPUT (tty)), &buf);
EMACS_SET_TTY (fileno (TTY_INPUT (tty)), &buf, 0);
if (tty->input) /* Is the device suspended? */
{
EMACS_GET_TTY (fileno (tty->input), &buf);
EMACS_SET_TTY (fileno (tty->input), &buf, 0);
}
}
}
#endif /* not MSDOS */
@ -322,7 +326,7 @@ stuff_char (char c)
/* Should perhaps error if in batch mode */
#ifdef TIOCSTI
ioctl (fileno (TTY_INPUT (CURTTY())), TIOCSTI, &c);
ioctl (fileno (CURTTY()->input), TIOCSTI, &c);
#else /* no TIOCSTI */
error ("Cannot stuff terminal input characters in this version of Unix");
#endif /* no TIOCSTI */
@ -1005,7 +1009,7 @@ request_sigio ()
return;
/* XXX CURTTY() is bogus here. */
ioctl (fileno (TTY_INPUT (CURTTY ())), FIOASYNC, &on);
ioctl (fileno (CURTTY ()->input), FIOASYNC, &on);
interrupts_deferred = 0;
}
@ -1018,7 +1022,7 @@ unrequest_sigio ()
return;
/* XXX CURTTY() is bogus here. */
ioctl (fileno (TTY_INPUT (CURTTY ())), FIOASYNC, &off);
ioctl (fileno (CURTTY ()->input), FIOASYNC, &off);
interrupts_deferred = 1;
}
@ -1366,6 +1370,9 @@ nil means don't delete them until `list-processes' is run. */);
if (noninteractive)
return;
if (!tty_out->output)
return; /* The tty is suspended. */
#ifdef VMS
if (!input_ef)
input_ef = get_kbd_event_flag ();
@ -1404,13 +1411,13 @@ nil means don't delete them until `list-processes' is run. */);
unconditionally will not cause any problems. */
if (! read_socket_hook && EQ (Vinitial_window_system, Qnil))
#endif
narrow_foreground_group (fileno (TTY_INPUT (tty_out)));
narrow_foreground_group (fileno (tty_out->input));
#endif
if (! tty_out->old_tty)
tty_out->old_tty = (struct emacs_tty *) xmalloc (sizeof (struct emacs_tty));
EMACS_GET_TTY (fileno (TTY_INPUT (tty_out)), tty_out->old_tty);
EMACS_GET_TTY (fileno (tty_out->input), tty_out->old_tty);
tty = *tty_out->old_tty;
@ -1626,23 +1633,23 @@ nil means don't delete them until `list-processes' is run. */);
dos_ttraw ();
#endif
EMACS_SET_TTY (fileno (TTY_INPUT (tty_out)), &tty, 0);
EMACS_SET_TTY (fileno (tty_out->input), &tty, 0);
/* This code added to insure that, if flow-control is not to be used,
we have an unlocked terminal at the start. */
#ifdef TCXONC
if (!tty_out->flow_control) ioctl (fileno (TTY_INPUT (tty_out)), TCXONC, 1);
if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1);
#endif
#ifndef APOLLO
#ifdef TIOCSTART
if (!tty_out->flow_control) ioctl (fileno (TTY_INPUT (tty_out)), TIOCSTART, 0);
if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0);
#endif
#endif
#if defined (HAVE_TERMIOS) || defined (HPUX9)
#ifdef TCOON
if (!tty_out->flow_control) tcflow (fileno (TTY_INPUT (tty_out)), TCOON);
if (!tty_out->flow_control) tcflow (fileno (tty_out->input), TCOON);
#endif
#endif
@ -1662,7 +1669,7 @@ nil means don't delete them until `list-processes' is run. */);
#ifdef VMS
/* Appears to do nothing when in PASTHRU mode.
SYS$QIOW (0, fileno (TTY_INPUT (tty_out)), IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
SYS$QIOW (0, fileno (tty_out->input), IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
interrupt_signal, oob_chars, 0, 0, 0, 0);
*/
queue_kbd_input (0);
@ -1673,10 +1680,10 @@ nil means don't delete them until `list-processes' is run. */);
#ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
if (interrupt_input)
{
old_fcntl_owner[fileno (TTY_INPUT (tty_out))] =
fcntl (fileno (TTY_INPUT (tty_out)), F_GETOWN, 0);
fcntl (fileno (TTY_INPUT (tty_out)), F_SETOWN, getpid ());
init_sigio (fileno (TTY_INPUT (tty_out)));
old_fcntl_owner[fileno (tty_out->input)] =
fcntl (fileno (tty_out->input), F_GETOWN, 0);
fcntl (fileno (tty_out->input), F_SETOWN, getpid ());
init_sigio (fileno (tty_out->input));
}
#endif /* F_GETOWN */
#endif /* F_SETOWN_BUG */
@ -1684,7 +1691,7 @@ nil means don't delete them until `list-processes' is run. */);
#ifdef BSD4_1
if (interrupt_input)
init_sigio (fileno (TTY_INPUT (tty_out)));
init_sigio (fileno (tty_out->input));
#endif
#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. */);
/* This symbol is defined on recent USG systems.
Someone says without this call USG won't really buffer the file
even with a call to setbuf. */
setvbuf (TTY_OUTPUT (tty_out), (char *) _sobuf, _IOFBF, sizeof _sobuf);
setvbuf (tty_out->output, (char *) _sobuf, _IOFBF, sizeof _sobuf);
#else
setbuf (TTY_OUTPUT (tty_out), (char *) _sobuf);
setbuf (tty_out->output, (char *) _sobuf);
#endif
tty_set_terminal_modes (tty_out->display);
@ -1867,10 +1874,13 @@ reset_sys_modes (tty_out)
if (!tty_out->term_initted)
return;
if (!tty_out->output)
return; /* The tty is suspended. */
/* Go to and clear the last line of the terminal. */
cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
/* Code adapted from tty_clear_end_of_line. */
if (tty_out->TS_clr_line)
{
@ -1880,13 +1890,13 @@ reset_sys_modes (tty_out)
{ /* have to do it the hard way */
int i;
turn_off_insert (tty_out);
for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++)
{
fputc (' ', TTY_OUTPUT (tty_out));
}
{
fputc (' ', tty_out->output);
}
}
cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
fflush (tty_out->output);
@ -1902,11 +1912,11 @@ reset_sys_modes (tty_out)
#endif
tty_reset_terminal_modes (tty_out->display);
fflush (TTY_OUTPUT (tty_out));
fflush (tty_out->output);
#ifdef BSD_SYSTEM
#ifndef BSD4_1
/* Avoid possible loss of output when changing terminal modes. */
fsync (fileno (TTY_OUTPUT (tty_out)));
fsync (fileno (tty_out->output));
#endif
#endif
@ -1915,24 +1925,24 @@ reset_sys_modes (tty_out)
#ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
if (interrupt_input)
{
reset_sigio (fileno (TTY_INPUT (tty_out)));
fcntl (fileno (TTY_INPUT (tty_out)), F_SETOWN,
old_fcntl_owner[fileno (TTY_INPUT (tty_out))]);
reset_sigio (fileno (tty_out->input));
fcntl (fileno (tty_out->input), F_SETOWN,
old_fcntl_owner[fileno (tty_out->input)]);
}
#endif /* F_SETOWN */
#endif /* F_SETOWN_BUG */
#ifdef O_NDELAY
fcntl (fileno (TTY_INPUT (tty_out)), F_SETFL,
fcntl (fileno (TTY_INPUT (tty_out)), F_GETFL, 0) & ~O_NDELAY);
fcntl (fileno (tty_out->input), F_SETFL,
fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY);
#endif
#endif /* F_SETFL */
#ifdef BSD4_1
if (interrupt_input)
reset_sigio (fileno (TTY_INPUT (tty_out)));
reset_sigio (fileno (tty_out->input));
#endif /* BSD4_1 */
if (tty_out->old_tty)
while (EMACS_SET_TTY (fileno (TTY_INPUT (tty_out)),
while (EMACS_SET_TTY (fileno (tty_out->input),
tty_out->old_tty, 0) < 0 && errno == EINTR)
;
@ -1952,7 +1962,7 @@ reset_sys_modes (tty_out)
#endif
#ifdef BSD_PGRPS
widen_foreground_group (fileno (TTY_INPUT (tty_out)));
widen_foreground_group (fileno (tty_out->input));
#endif
}
@ -2017,9 +2027,9 @@ init_vms_input ()
{
int status;
if (fileno (TTY_INPUT (CURTTY())) == 0)
if (fileno (CURTTY ()->input)) == 0)
{
status = SYS$ASSIGN (&input_dsc, &fileno (TTY_INPUT (CURTTY())), 0, 0);
status = SYS$ASSIGN (&input_dsc, &fileno (CURTTY ()->input)), 0, 0);
if (! (status & 1))
LIB$STOP (status);
}
@ -2030,7 +2040,7 @@ init_vms_input ()
void
stop_vms_input ()
{
return SYS$DASSGN (fileno (TTY_INPUT (CURTTY())));
return SYS$DASSGN (fileno (CURTTY ()->input)));
}
short input_buffer;
@ -2046,7 +2056,7 @@ queue_kbd_input ()
waiting_for_ast = 0;
stop_input = 0;
status = SYS$QIO (0, fileno (TTY_INPUT (CURTTY())), IO$_READVBLK,
status = SYS$QIO (0, fileno (CURTTY()->input), IO$_READVBLK,
&input_iosb, kbd_input_ast, 1,
&input_buffer, 1, 0, terminator_mask, 0, 0);
}
@ -2163,7 +2173,7 @@ end_kbd_input ()
#endif
if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
{
SYS$CANCEL (fileno (TTY_INPUT (CURTTY())));
SYS$CANCEL (fileno (CURTTY()->input));
return;
}
@ -2172,7 +2182,7 @@ end_kbd_input ()
SYS$CLREF (input_ef);
waiting_for_ast = 1;
stop_input = 1;
SYS$CANCEL (fileno (TTY_INPUT (CURTTY())));
SYS$CANCEL (fileno (CURTTY()->input));
SYS$SETAST (1);
SYS$WAITFR (input_ef);
waiting_for_ast = 0;

View File

@ -106,9 +106,15 @@ void delete_tty_output P_ ((struct frame *));
Lisp_Object Vring_bell_function;
/* Functions to call after a tty was deleted. */
/* Functions to call after deleting a tty. */
Lisp_Object Vdelete_tty_after_functions;
/* Functions to call after suspending a tty. */
Lisp_Object Vsuspend_tty_functions;
/* Functions to call after resuming a tty. */
Lisp_Object Vresume_tty_functions;
/* Chain of all displays currently in use. */
struct display *display_list;
@ -231,10 +237,13 @@ tty_set_terminal_modes (struct display *display)
{
struct tty_display_info *tty = display->display_info.tty;
OUTPUT_IF (tty, tty->TS_termcap_modes);
OUTPUT_IF (tty, tty->TS_cursor_visible);
OUTPUT_IF (tty, tty->TS_keypad_mode);
losecursor (tty);
if (tty->output)
{
OUTPUT_IF (tty, tty->TS_termcap_modes);
OUTPUT_IF (tty, tty->TS_cursor_visible);
OUTPUT_IF (tty, tty->TS_keypad_mode);
losecursor (tty);
}
}
/* Reset termcap modes before exiting Emacs. */
@ -243,16 +252,19 @@ void
tty_reset_terminal_modes (struct display *display)
{
struct tty_display_info *tty = display->display_info.tty;
turn_off_highlight (tty);
turn_off_insert (tty);
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);
/* Output raw CR so kernel can track the cursor hpos. */
current_tty = tty;
cmputc ('\r');
if (tty->output)
{
turn_off_highlight (tty);
turn_off_insert (tty);
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);
/* Output raw CR so kernel can track the cursor hpos. */
current_tty = tty;
cmputc ('\r');
}
}
void
@ -619,9 +631,9 @@ tty_clear_end_of_line (int first_unused_hpos)
for (i = curX (tty); i < first_unused_hpos; i++)
{
if (TTY_TERMSCRIPT (tty))
fputc (' ', TTY_TERMSCRIPT (tty));
fputc (' ', TTY_OUTPUT (tty));
if (tty->termscript)
fputc (' ', tty->termscript);
fputc (' ', tty->output);
}
cmplus (tty, first_unused_hpos - curX (tty));
}
@ -807,12 +819,12 @@ tty_write_glyphs (struct glyph *string, int len)
if (produced > 0)
{
fwrite (conversion_buffer, 1, produced,
TTY_OUTPUT (tty));
if (ferror (TTY_OUTPUT (tty)))
clearerr (TTY_OUTPUT (tty));
if (TTY_TERMSCRIPT (tty))
tty->output);
if (ferror (tty->output))
clearerr (tty->output);
if (tty->termscript)
fwrite (conversion_buffer, 1, produced,
TTY_TERMSCRIPT (tty));
tty->termscript);
}
len -= consumed;
n -= consumed;
@ -833,12 +845,12 @@ tty_write_glyphs (struct glyph *string, int len)
if (terminal_coding.produced > 0)
{
fwrite (conversion_buffer, 1, terminal_coding.produced,
TTY_OUTPUT (tty));
if (ferror (TTY_OUTPUT (tty)))
clearerr (TTY_OUTPUT (tty));
if (TTY_TERMSCRIPT (tty))
tty->output);
if (ferror (tty->output))
clearerr (tty->output);
if (tty->termscript)
fwrite (conversion_buffer, 1, terminal_coding.produced,
TTY_TERMSCRIPT (tty));
tty->termscript);
}
}
@ -927,12 +939,12 @@ tty_insert_glyphs (struct glyph *start, int len)
if (produced > 0)
{
fwrite (conversion_buffer, 1, produced,
TTY_OUTPUT (tty));
if (ferror (TTY_OUTPUT (tty)))
clearerr (TTY_OUTPUT (tty));
if (TTY_TERMSCRIPT (tty))
tty->output);
if (ferror (tty->output))
clearerr (tty->output);
if (tty->termscript)
fwrite (conversion_buffer, 1, produced,
TTY_TERMSCRIPT (tty));
tty->termscript);
}
OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
@ -2240,7 +2252,11 @@ term_init (char *name, char *terminal_type, int must_succeed)
display = get_named_tty_display (name);
if (display)
return display; /* We have already opened a display there. */
{
if (! display->display_info.tty->input)
error ("%s already has a suspended frame on it, can't open it twice", name);
return display;
}
display = create_display ();
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.",
/* Get frame size from system, or else from termcap. */
{
int height, width;
get_tty_size (fileno (TTY_INPUT (tty)), &width, &height);
get_tty_size (fileno (tty->input), &width, &height);
FrameCols (tty) = width;
FrameRows (tty) = height;
}
@ -2735,7 +2751,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
&& tty->TS_end_standout_mode
&& !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
UseTabs (tty) = tabs_safe_p (fileno (TTY_INPUT (tty))) && TabWidth (tty) == 8;
UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
display->scroll_region_ok
= (tty->Wcm->cm_abs
@ -2754,7 +2770,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
display->fast_clear_end_of_line = tty->TS_clr_line != 0;
init_baud_rate (fileno (TTY_INPUT (tty)));
init_baud_rate (fileno (tty->input));
#ifdef AIXHFT
/* The HFT system on AIX doesn't optimize for scrolling, so it's
@ -3067,6 +3083,134 @@ delete_display (struct display *dev)
xfree (dev);
}
DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
doc: /* Suspend the terminal device TTY.
The terminal is restored to its default state, and Emacs closes all
access to the terminal device. Frames that use the device are not
deleted, but input is not read from them and if they change, their
display is not updated.
TTY may a string (a device name), a frame, or nil for the display
device of the currently selected frame.
This function runs `suspend-tty-functions' after suspending the
device. The functions are run with one arg, the name of the terminal
device.
`suspend-tty' does nothing if it is called on an already suspended
device.
A suspended terminal device may be resumed by calling `resume-tty' on
it. */)
(tty)
Lisp_Object tty;
{
struct display *d = get_tty_display (tty);
FILE *f;
if (!d)
error ("Unknown tty device");
f = d->display_info.tty->input;
if (f)
{
reset_sys_modes (d->display_info.tty);
delete_keyboard_wait_descriptor (fileno (f));
fclose (f);
if (f != d->display_info.tty->output)
fclose (d->display_info.tty->output);
d->display_info.tty->input = 0;
d->display_info.tty->output = 0;
if (FRAMEP (d->display_info.tty->top_frame))
FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 0);
/* Run `suspend-tty-functions'. */
if (!NILP (Vrun_hooks))
{
Lisp_Object args[2];
args[0] = intern ("suspend-tty-functions");
if (d->display_info.tty->name)
{
args[1] = build_string (d->display_info.tty->name);
}
else
args[1] = Qnil;
Frun_hook_with_args (2, args);
}
}
return Qnil;
}
DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
doc: /* Resume the previously suspended terminal device TTY.
The terminal is opened and reinitialized. Frames that used the
suspended device are revived.
This function runs `resume-tty-functions' after resuming the device.
The functions are run with one arg, the name of the terminal device.
`resume-tty' does nothing if it is called on a device that is not
suspended.
TTY may a string (a device name), a frame, or nil for the display
device of the currently selected frame. */)
(tty)
Lisp_Object tty;
{
struct display *d = get_tty_display (tty);
int fd;
if (!d)
error ("Unknown tty device");
if (!d->display_info.tty->input)
{
fd = emacs_open (d->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
#ifdef TIOCNOTTY
/* Drop our controlling tty if it is the same device. */
if (ioctl (fd, TIOCNOTTY, 0) != -1)
{
no_controlling_tty = 1;
}
#endif
d->display_info.tty->output = fdopen (fd, "w+");
d->display_info.tty->input = d->display_info.tty->output;
add_keyboard_wait_descriptor (fd);
if (FRAMEP (d->display_info.tty->top_frame))
FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 1);
init_sys_modes (d->display_info.tty);
/* Run `suspend-tty-functions'. */
if (!NILP (Vrun_hooks))
{
Lisp_Object args[2];
args[0] = intern ("resume-tty-functions");
if (d->display_info.tty->name)
{
args[1] = build_string (d->display_info.tty->name);
}
else
args[1] = Qnil;
Frun_hook_with_args (2, args);
}
}
return Qnil;
}
void
@ -3092,6 +3236,20 @@ The functions are run with one argument, the name of the tty to be deleted.
See `delete-tty'. */);
Vdelete_tty_after_functions = Qnil;
DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
doc: /* Functions to be run after suspending a tty.
The functions are run with one argument, the name of the tty to be suspended.
See `suspend-tty'. */);
Vsuspend_tty_functions = Qnil;
DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
doc: /* Functions to be run after resuming a tty.
The functions are run with one argument, the name of the tty that was revived.
See `resume-tty'. */);
Vresume_tty_functions = Qnil;
Qframe_tty_name = intern ("frame-tty-name");
staticpro (&Qframe_tty_name);
@ -3103,6 +3261,8 @@ See `delete-tty'. */);
defsubr (&Sframe_tty_name);
defsubr (&Sframe_tty_type);
defsubr (&Sdelete_tty);
defsubr (&Ssuspend_tty);
defsubr (&Sresume_tty);
Fprovide (intern ("multi-tty"), Qnil);

View File

@ -42,8 +42,10 @@ struct tty_display_info
/* Input/output */
FILE *input; /* The stream to be used for terminal input. */
FILE *output; /* The stream to be used for terminal output. */
FILE *input; /* The stream to be used for terminal input.
NULL if the terminal is suspended. */
FILE *output; /* The stream to be used for terminal output.
NULL if the terminal is suspended. */
FILE *termscript; /* If nonzero, send all terminal output
characters to this stream also. */
@ -200,9 +202,5 @@ extern struct tty_display_info *tty_list;
#define CURTTY() FRAME_TTY (SELECTED_FRAME())
#define TTY_INPUT(t) ((t)->input)
#define TTY_OUTPUT(t) ((t)->output)
#define TTY_TERMSCRIPT(t) ((t)->termscript)
/* arch-tag: bf9f0d49-842b-42fb-9348-ec8759b27193
(do not change this comment) */

View File

@ -513,7 +513,6 @@ struct display
frames on the display when it calls this hook, so infinite
recursion is prevented. */
void (*delete_display_hook) P_ ((struct display *));
};