Mercurial > emacs
diff lib-src/emacsclient.c @ 53229:33c3c7c16e13
lib-src/emacsclient.c: Implemented --here option (open a new Emacs tty). Needs more work.
(here): New variable.
(decode_options): Use it.
(ec_get_tty, ec_set_tty, init_tty, window_change, hang_up_signal): New functions.
(window_change_signal, init_signals, reset_tty, init_pty, copy_from_to): Ditto.
(pty_conversation): Ditto.
(main): Use them.
(master, pty_name, old_tty, tty, old_tty_valid, tty_erase_char): New variables.
(flow_control, meta_key, _sobuf, in_conversation, quit_conversation): Ditto.
lisp/server.el (server-process-filter): Added support for opening a new terminal frame.
dispextern.h (get_frame_size): Renamed to get_tty_size, added tty_output parameter.
dispnew.c (Fredraw_frame): fflush the current terminal instead of stdout.
(direct_output_for_insert, direct_output_forward_char, update_frame_1): Ditto.
(Fding, bitch_at_user): Ditto.
(update_frame_1): Count pending output for current terminal instead of stdout.
(window_change_signal): Resize all terminals.
(change_frame_size): Don't resize all terminals to the same size.
frame.c (Vterminal_frame): Removed.
(syms_of_frame): Removed declaration of Vterminal_frame.
(make_terminal_frame): Set the top frame of the terminal to the new frame.
(Fmake_terminal_frame): Get a new frame size from get_tty_size, don't copy it.
(do_switch_frame): Handle terminal frame visibility.
(next_frame, prev_frame): Skip over frames on different terminals.
frame.h (Vterminal_frame): Removed.
keyboard.c (input_fd): Removed.
(read_avail_input): Removed first argument from read_socket_hook.
Try to read from each available tty, until one succeeds.
(Fsuspend_emacs): Don't suspend if there are multiple terminals.
lisp.h (get_frame_size): Removed superflous declaration.
xterm.c (Xtread_socket): Removed first parameter.
macterm.h (XTread_socket): Ditto.
w32inevt.c (w32_console_read_socket): Ditto.
w32term.c (w32_read_socket): Ditto.
sysdep.c (input_fd): Removed.
(change_input_fd): Removed.
(discard_tty_input): Discard pending input on _all_ input descriptors.
(stuff_char, tabs_safe_p): Use current terminal instead of input_fd.
(init_baud_rate, request_sigio, unrequest_sigio): Ditto.
(init_sys_modes, reset_sys_modes): Ditto.
(narrow_foreground_group, widen_foreground_group): Use stdin.
(init_sys_modes, reset_sys_modes): otty parameter renamed to tty_out.
(get_frame_size): Renamed to get_tty_size, added tty_out parameter.
term.c (read_socket_hook): Removed first parameter.
(clear_end_of_line): Use updating_frame, if possible.
(write_glyphs, insert_glyphs, ins_del_lines): Ditto.
(term_init): Renamed get_frame_size to get_tty_size.
termchar.h (struct tty_output): New entries: top_frame,
previous_terminal_frame.
termhooks.h (read_socket_hook): Removed first parameter.
window.c (init_window_once): Removed reference to Vterminal_frame.
xdisp.c (previous_terminal_frame): Moved to struct tty_output.
(redisplay_internal): Updated to use previous_terminal_frame in tty_output.
Allow for simultaneous refresh of multiple ttys.
git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-5
author | Karoly Lorentey <lorentey@elte.hu> |
---|---|
date | Fri, 26 Dec 2003 04:24:54 +0000 |
parents | 5c74e66d6c36 |
children | 22aaf1e5fbe6 |
line wrap: on
line diff
--- a/lib-src/emacsclient.c Thu Dec 25 07:36:05 2003 +0000 +++ b/lib-src/emacsclient.c Fri Dec 26 04:24:54 2003 +0000 @@ -41,6 +41,54 @@ # include <pwd.h> #endif /* not VMS */ + +/****************************************/ + +#include <errno.h> +#include <signal.h> + +#ifndef INCLUDED_FCNTL +#define INCLUDED_FCNTL +#include <fcntl.h> +#endif + +#ifdef HAVE_TERMIOS +#ifndef NO_TERMIO +#include <termio.h> +#endif +#include <termios.h> +#endif /* not HAVE_TERMIOS */ + +#ifdef __GNU_LIBRARY__ +#include <sys/ioctl.h> +#include <termios.h> +#endif + +#if (defined (POSIX) || defined (NEED_UNISTD_H)) && defined (HAVE_UNISTD_H) +#include <unistd.h> +#endif + + + +/* Try to establish the correct character to disable terminal functions + in a system-independent manner. Note that USG (at least) define + _POSIX_VDISABLE as 0! */ + +#ifdef _POSIX_VDISABLE +#define CDISABLE _POSIX_VDISABLE +#else /* not _POSIX_VDISABLE */ +#ifdef CDEL +#undef CDISABLE +#define CDISABLE CDEL +#else /* not CDEL */ +#define CDISABLE 255 +#endif /* not CDEL */ +#endif /* not _POSIX_VDISABLE */ + + + +/****************************************/ + char *getenv (), *getwd (); char *getcwd (); @@ -63,6 +111,9 @@ /* The display on which Emacs should work. --display. */ char *display = NULL; +/* Nonzero means open a new Emacs frame on the current terminal. */ +int here = 0; + /* If non-NULL, the name of an editor to fallback to if the server is not running. --alternate-editor. */ const char * alternate_editor = NULL; @@ -78,6 +129,7 @@ { "eval", no_argument, NULL, 'e' }, { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, + { "here", no_argument, NULL, 'h' }, { "alternate-editor", required_argument, NULL, 'a' }, { "socket-name", required_argument, NULL, 's' }, { "display", required_argument, NULL, 'd' }, @@ -95,7 +147,7 @@ while (1) { int opt = getopt_long (argc, argv, - "VHnea:s:d:", longopts, 0); + "VHnea:s:d:h", longopts, 0); if (opt == EOF) break; @@ -134,6 +186,10 @@ exit (0); break; + case 'h': + here = 1; + break; + case 'H': print_help_and_exit (); break; @@ -144,6 +200,12 @@ break; } } + + if (here) { + nowait = 0; + display = 0; + } + } void @@ -157,6 +219,7 @@ The following OPTIONS are accepted:\n\ -V, --version Just print a version info and return\n\ -H, --help Print this usage information message\n\ +-h, --here Open a new Emacs frame on the current terminal\n\ -n, --no-wait Don't wait for the server to return\n\ -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ -d, --display=DISPLAY Visit the file in the given display\n\ @@ -247,6 +310,455 @@ } } + +#ifdef HAVE_TERMIOS + +/* Adapted from emacs_get_tty() in sysdep.c. */ +int +ec_get_tty (int fd, struct termios *settings) +{ + bzero (settings, sizeof (struct termios)); + if (tcgetattr (fd, settings) < 0) + return -1; + return 0; +} + +/* Adapted from emacs_set_tty() in sysdep.c. */ +int +ec_set_tty (int fd, struct termios *settings, int flushp) +{ + /* Set the primary parameters - baud rate, character size, etcetera. */ + + int i; + /* We have those nifty POSIX tcmumbleattr functions. + William J. Smith <wjs@wiis.wang.com> writes: + "POSIX 1003.1 defines tcsetattr to return success if it was + able to perform any of the requested actions, even if some + of the requested actions could not be performed. + We must read settings back to ensure tty setup properly. + AIX requires this to keep tty from hanging occasionally." */ + /* This make sure that we don't loop indefinitely in here. */ + for (i = 0 ; i < 10 ; i++) + if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, settings) < 0) + { + if (errno == EINTR) + continue; + else + return -1; + } + else + { + struct termios new; + + bzero (&new, sizeof (new)); + /* Get the current settings, and see if they're what we asked for. */ + tcgetattr (fd, &new); + /* We cannot use memcmp on the whole structure here because under + * aix386 the termios structure has some reserved field that may + * not be filled in. + */ + if ( new.c_iflag == settings->c_iflag + && new.c_oflag == settings->c_oflag + && new.c_cflag == settings->c_cflag + && new.c_lflag == settings->c_lflag + && memcmp (new.c_cc, settings->c_cc, NCCS) == 0) + break; + else + continue; + } + return 0; +} + +int master; +char *pty_name; + +struct termios old_tty; +struct termios tty; +int old_tty_valid; + +int tty_erase_char; +int flow_control = 0; +int meta_key = 0; +char _sobuf[BUFSIZ]; + +/* Adapted from init_sys_modes() in sysdep.c. */ +int +init_tty () +{ + if (! isatty (0)) + { + fprintf (stderr, "%s: Input is not a terminal", "init_tty"); + return 0; + } + + ec_get_tty (0, &old_tty); + old_tty_valid = 1; + tty = old_tty; + + tty_erase_char = old_tty.c_cc[VERASE]; + + tty.c_iflag |= (IGNBRK); /* Ignore break condition */ + tty.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */ +#ifdef INLCR + tty.c_iflag &= ~INLCR; /* Disable map of NL to CR on input */ +#endif +#ifdef ISTRIP + tty.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */ +#endif + tty.c_lflag &= ~ECHO; /* Disable echo */ + tty.c_lflag &= ~ICANON; /* Disable erase/kill processing */ +#ifdef IEXTEN + tty.c_lflag &= ~IEXTEN; /* Disable other editing characters. */ +#endif + tty.c_lflag |= ISIG; /* Enable signals */ + if (flow_control) + { + tty.c_iflag |= IXON; /* Enable start/stop output control */ +#ifdef IXANY + tty.c_iflag &= ~IXANY; +#endif /* IXANY */ + } + else + tty.c_iflag &= ~IXON; /* Disable start/stop output control */ + tty.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL + on output */ + tty.c_oflag &= ~TAB3; /* Disable tab expansion */ +#ifdef CS8 + if (meta_key) + { + tty.c_cflag |= CS8; /* allow 8th bit on input */ + tty.c_cflag &= ~PARENB; /* Don't check parity */ + } +#endif + tty.c_cc[VINTR] = CDISABLE; + tty.c_cc[VQUIT] = CDISABLE; + tty.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */ + tty.c_cc[VTIME] = 0; /* no matter how long that takes. */ +#ifdef VSWTCH + tty.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use of C-z */ +#endif + +#ifdef VSUSP + tty.c_cc[VSUSP] = CDISABLE; /* Turn off mips handling of C-z. */ +#endif /* VSUSP */ +#ifdef V_DSUSP + tty.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y. */ +#endif /* V_DSUSP */ +#ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */ + tty.c_cc[VDSUSP] = CDISABLE; +#endif /* VDSUSP */ +#ifdef VLNEXT + tty.c_cc[VLNEXT] = CDISABLE; +#endif /* VLNEXT */ +#ifdef VREPRINT + tty.c_cc[VREPRINT] = CDISABLE; +#endif /* VREPRINT */ +#ifdef VWERASE + tty.c_cc[VWERASE] = CDISABLE; +#endif /* VWERASE */ +#ifdef VDISCARD + tty.c_cc[VDISCARD] = CDISABLE; +#endif /* VDISCARD */ + + if (flow_control) + { +#ifdef VSTART + tty.c_cc[VSTART] = '\021'; +#endif /* VSTART */ +#ifdef VSTOP + tty.c_cc[VSTOP] = '\023'; +#endif /* VSTOP */ + } + else + { +#ifdef VSTART + tty.c_cc[VSTART] = CDISABLE; +#endif /* VSTART */ +#ifdef VSTOP + tty.c_cc[VSTOP] = CDISABLE; +#endif /* VSTOP */ + } + +#ifdef SET_LINE_DISCIPLINE + /* Need to explicitly request TERMIODISC line discipline or + Ultrix's termios does not work correctly. */ + tty.c_line = SET_LINE_DISCIPLINE; +#endif + +#ifdef AIX +#ifndef IBMR2AIX + /* AIX enhanced edit loses NULs, so disable it. */ + tty.c_line = 0; + tty.c_iflag &= ~ASCEDIT; +#else + tty.c_cc[VSTRT] = 255; + tty.c_cc[VSTOP] = 255; + tty.c_cc[VSUSP] = 255; + tty.c_cc[VDSUSP] = 255; +#endif /* IBMR2AIX */ + if (flow_control) + { +#ifdef VSTART + tty.c_cc[VSTART] = '\021'; +#endif /* VSTART */ +#ifdef VSTOP + tty.c_cc[VSTOP] = '\023'; +#endif /* VSTOP */ + } + /* Also, PTY overloads NUL and BREAK. + don't ignore break, but don't signal either, so it looks like NUL. + This really serves a purpose only if running in an XTERM window + or via TELNET or the like, but does no harm elsewhere. */ + tty.c_iflag &= ~IGNBRK; + tty.c_iflag &= ~BRKINT; +#endif /* AIX */ + + ec_set_tty (0, &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 (!flow_control) ioctl (0, TCXONC, 1); +#endif +#ifndef APOLLO +#ifdef TIOCSTART + if (!flow_control) ioctl (0, TIOCSTART, 0); +#endif +#endif + +#if defined (HAVE_TERMIOS) || defined (HPUX9) +#ifdef TCOON + if (!flow_control) tcflow (0, TCOON); +#endif +#endif + +#ifdef _IOFBF + /* 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 (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf); +#else + setbuf (stdout, (char *) _sobuf); +#endif + + return 1; +} + +void +window_change () +{ + int width, height; + +#ifdef TIOCGWINSZ + { + /* BSD-style. */ + struct winsize size; + + if (ioctl (0, TIOCGWINSZ, &size) == -1) + width = height = 0; + else + { + width = size.ws_col; + height = size.ws_row; + } + } +#else +#ifdef TIOCGSIZE + { + /* SunOS - style. */ + struct ttysize size; + + if (ioctl (0, TIOCGSIZE, &size) == -1) + width = height = 0; + else + { + width = size.ts_cols; + height = size.ts_lines; + } + } +#endif /* not SunOS-style */ +#endif /* not BSD-style */ + +#ifdef TIOCSWINSZ + { + /* BSD-style. */ + struct winsize size; + size.ws_row = height; + size.ws_col = width; + + ioctl (master, TIOCSWINSZ, &size); + } +#else +#ifdef TIOCSSIZE + { + /* SunOS - style. */ + struct ttysize size; + size.ts_lines = height; + size.ts_cols = width; + + ioctl (master, TIOCGSIZE, &size); + } +#endif /* not SunOS-style */ +#endif /* not BSD-style */ +} + +int in_conversation = 0; +int quit_conversation = 0; + +SIGTYPE +hang_up_signal (int signalnum) +{ + int old_errno = errno; + + if (! in_conversation) + return; + + quit_conversation = 1; + + errno = old_errno; +} + +SIGTYPE +window_change_signal (int signalnum) +{ + int old_errno = errno; + + if (! in_conversation) + goto end; + + window_change(); + + end: + signal (SIGWINCH, window_change_signal); + errno = old_errno; +} + +int +init_signals () +{ + /* Set up signal handlers. */ + signal (SIGWINCH, window_change_signal); + signal (SIGHUP, hang_up_signal); + + return 1; +} + + + +/* Adapted from reset_sys_modes in sysdep.c. */ +int +reset_tty () +{ + fflush (stdout); +#ifdef BSD_SYSTEM +#ifndef BSD4_1 + /* Avoid possible loss of output when changing terminal modes. */ + fsync (fileno (stdout)); +#endif +#endif + +#ifdef F_SETFL +#ifdef O_NDELAY + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NDELAY); +#endif +#endif /* F_SETFL */ + + if (old_tty_valid) + while (ec_set_tty (0, &old_tty, 0) < 0 && errno == EINTR) + ; + + return 1; +} + + +int +init_pty () +{ + master = getpt (); + if (master < 0) + return 0; + + if (grantpt (master) < 0 || unlockpt (master) < 0) + goto close_master; + pty_name = strdup (ptsname (master)); + if (! pty_name) + goto close_master; + + /* Propagate window size. */ + window_change (); + + return 1; + + close_master: + close (master); + return 0; +} + +int +copy_from_to (int in, int out) +{ + static char buf[BUFSIZ]; + int nread = read (in, &buf, BUFSIZ); + if (nread == 0) + return 1; /* EOF */ + else if (nread < 0 && errno != EAGAIN) + return 0; /* Error */ + else if (nread > 0) + { + int r = 0; + int written = 0; + + do { + r = write (out, &buf, nread); + } while ((r < 0 && errno == EAGAIN) + || (r > 0 && (written += r) && written != nread)); + + if (r < 0) + return 0; /* Error */ + } + return 1; +} + +int +pty_conversation () +{ + fd_set set; + + in_conversation = 1; + + while (! quit_conversation) { + int res; + + FD_ZERO (&set); + FD_SET (master, &set); + FD_SET (1, &set); + res = select (FD_SETSIZE, &set, NULL, NULL, NULL); + if (res < 0) + { + if (errno != EINTR) + return 0; + } + else if (res > 0) + { + if (FD_ISSET (master, &set)) + { + /* Copy Emacs output to stdout. */ + if (! copy_from_to (master, 0)) + return 1; + } + if (FD_ISSET (1, &set)) + { + /* Forward user input to Emacs. */ + if (! copy_from_to (1, master)) + return 1; + } + } + } + return 1; +} + +#endif /* HAVE_TERMIOS */ #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM) @@ -312,7 +824,7 @@ /* Process options. */ decode_options (argc, argv); - if ((argc - optind < 1) && !eval) + if ((argc - optind < 1) && !eval && !here) { fprintf (stderr, "%s: file name or argument required\n", progname); fprintf (stderr, "Try `%s --help' for more information\n", progname); @@ -484,6 +996,38 @@ fprintf (out, " "); } + if (here) + { + if (! init_signals ()) + { + fprintf (stderr, "%s: ", argv[0]); + perror ("fdopen"); + fail (argc, argv); + } + + if (! init_tty ()) + { + reset_tty (); + fprintf (stderr, "%s: ", argv[0]); + perror ("fdopen"); + fail (argc, argv); + } + + if (! init_pty ()) + { + reset_tty (); + fprintf (stderr, "%s: ", argv[0]); + perror ("fdopen"); + fail (argc, argv); + } + + fprintf (out, "-pty "); + quote_file_name (pty_name, out); + fprintf (out, " "); + quote_file_name (getenv("TERM"), out); + fprintf (out, " "); + } + if ((argc - optind > 0)) { for (i = optind; i < argc; i++) @@ -512,11 +1056,14 @@ } else { - while ((str = fgets (string, BUFSIZ, stdin))) - { - quote_file_name (str, out); - } - fprintf (out, " "); + if (!here) + { + while ((str = fgets (string, BUFSIZ, stdin))) + { + quote_file_name (str, out); + } + fprintf (out, " "); + } } fprintf (out, "\n"); @@ -524,8 +1071,25 @@ /* Maybe wait for an answer. */ if (nowait) - return 0; + { + reset_tty (); + return 0; + } + if (here) + { + if (! pty_conversation ()) + { + reset_tty (); + fprintf (stderr, "%s: ", argv[0]); + perror ("fdopen"); + fail (argc, argv); + } + close (master); + reset_tty (); + return 0; + } + if (!eval) { printf ("Waiting for Emacs..."); @@ -546,6 +1110,7 @@ printf ("\n"); fflush (stdout); + reset_tty (); return 0; }