changeset 83416:4513d8dcdfd5

Reimplement and extend support for terminal-local environment variables. * lisp/termdev.el: New file. Move terminal parameter-related functions here from frame.el. (terminal-getenv, with-terminal-environment): Reimplement and extend. (terminal-setenv, terminal-setenv-internal): New functions. * lisp/frame.el (make-frame-on-tty, framep-on-display, suspend-frame): Extend doc string, update parameter names. (terminal-id, terminal-parameter-alist, terminal-parameters) (terminal-parameter-p, terminal-parameter, set-terminal-parameter) (terminal-handle-delete-frame, terminal-getenv, terminal-getenv) (with-terminal-environment): Move to termdev.el. * lisp/loadup.el: Load termdev as well. * lisp/Makefile.in (lisp, shortlisp): Add termdev.elc. * lisp/makefile.MPW (shortlisp): Ditto. * lisp/ebuff-menu.el (electric-buffer-menu-mode-map): Bind C-z to `suspend-frame', not `suspend-emacs'. * lisp/echistory.el (electric-history-map): Ditto. * lisp/ebrowse.el (ebrowse-electric-list-mode-map): Ditto. * lisp/ebrowse.el (ebrowse-electric-position-mode-map): Ditto. * lisp/startup.el (normal-splash-screen): Use `save-buffers-kill-display' instead of `save-buffers-kill-emacs'. * lisp/x-win.el (x-initialize-window-system): Add 'global-ok option to `terminal-getenv'. * src/term.c (suspend-tty): Update doc string. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-456
author Karoly Lorentey <lorentey@elte.hu>
date Thu, 22 Dec 2005 21:02:45 +0000
parents d2c799f58129
children fe870a866ce7
files README.multi-tty lisp/ebuff-menu.el lisp/echistory.el lisp/frame.el lisp/loadup.el lisp/progmodes/ebrowse.el lisp/startup.el lisp/term/x-win.el lisp/termdev.el mac/makefile.MPW src/Makefile.in src/print.c src/term.c
diffstat 13 files changed, 334 insertions(+), 202 deletions(-) [+]
line wrap: on
line diff
--- a/README.multi-tty	Tue Dec 20 21:35:03 2005 +0000
+++ b/README.multi-tty	Thu Dec 22 21:02:45 2005 +0000
@@ -89,7 +89,7 @@
 
 The multi-tty branch has been scheduled for inclusion in the next
 major release of Emacs (version 23).  I expect the merge into the
-development trunk to occur sometime during next year (2005), after the
+development trunk to occur sometime during next year (2006), after the
 merge of the Unicode branch.
 
 Tested on GNU/Linux, Solaris 8, FreeBSD and OpenBSD.  Please let me
@@ -140,36 +140,36 @@
   	  system-dependent source files need to be adapted
   	  accordingly.  The changes are mostly trivial, so almost
   	  anyone can help, if only by compiling the branch and
-  	  reporting the compiler errors.  (It is not worth to do this
-  	  yet, though.)
+  	  reporting the compiler errors.
 
 
 HOW TO GET THE BRANCH
 ---------------------
 
-The branch uses GNU Arch (http://www.gnuarch.org) for version control.
+The branch uses Bazaar 1 (http://bazaar.canonical.com) for version control.
 
 Retrieving the latest version of the branch:
 
-	tla register-archive -f http://lorentey.hu/arch/2004/
-	tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
+	baz register-archive -f http://aszt.inf.elte.hu/~lorentey/mirror/arch/2004
+	baz get lorentey@elte.hu--2004/emacs--multi-tty <directory>
 
-This incantation uses my private archive mirror that is hosted on a
-relatively low-bandwidth site; if you are outside Hungary, you will
-probably want to you use my secondary mirror: (Note that the -f option
-will overwrite the archive location if you have previously registered
-the Hungarian one.)
+This incantation uses an archive mirror that is hosted on a
+high-bandwidth site.  Please note that on average there is a two-hour
+delay for commits to arrive on this mirror.  My primary mirror is on the
+low-bandwidth http://lorentey.hu/ site:
 
-	tla register-archive -f http://aszt.inf.elte.hu/~lorentey/mirror/arch/2004
-	tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
+	baz register-archive -f http://lorentey.hu/arch/2004/
+	baz get lorentey@elte.hu--2004/emacs--multi-tty <directory>
 
-	http://aszt.inf.elte.hu/~lorentey/mirror/arch/2004
+This is "instantly" updated, but very slow from outside Hungary.
+(By "instantly" I mean as soon as I connect the notebook I work on to
+a network.  It could take days.)
 
 The Arch supermirror provides mirroring services for all public Arch
 repositories.  We have a mirror there, too, if you prefer.
 
-	tla register-archive -f http://mirrors.sourcecontrol.net/lorentey%40elte.hu--2004
-	tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
+	baz register-archive -f http://mirrors.sourcecontrol.net/lorentey%40elte.hu--2004
+	baz get lorentey@elte.hu--2004/emacs--multi-tty <directory>
 
 My GPG key id is 0FB27A3F; it is available from
 hkp://wwwkeys.eu.pgp.net/, or from my homepage at
@@ -179,16 +179,20 @@
 once you have a source tree, updating it to the latest revision will
 be _much_ faster.  Use the following command for the update:
 
-	tla replay
+	baz replay
 
-You can find more information about Arch on http://wiki.gnuarch.org/.
-It's a wonderful source control system, I highly recommend it.
+You can find more information about Bazaar on
+http://bazaar.canonical.com/.  It's a distributed source control
+system that is somewhat less broken than competing projects.
 
-If you don't have tla, the branch has a homepage from which you can
+If you don't have Bazaar, the branch has a homepage from which you can
 download conventional patches against Emacs CVS HEAD:
 
 	http://lorentey.hu/project/emacs.html
 
+I suggest you use Bazaar whenever feasible.
+
+
 DEBIAN PACKAGES
 ---------------
 
@@ -244,9 +248,10 @@
 also works.  Of course, you can create frames on more than two tty
 devices.
 
-Creating new frames on the same tty with C-x 5 2 works, and they
-behave the same way as in previous Emacs versions.  If you exit emacs,
-all terminals should be restored to their previous states.
+Creating new frames on the same tty with C-x 5 2 (make-frame-command)
+works, and they behave the same way as in previous Emacs versions.  If
+you exit emacs, all terminals should be restored to their previous
+states.
 
 This is work in progress, and probably full of bugs.  It is a good
 idea to run emacs from gdb, so that you'll have a live instance to
@@ -384,6 +389,8 @@
 
 *** talk.el has been extended for multiple tty support.
 
+*** C-z now invokes `suspend-frame', C-x C-c now invokes
+    `save-buffers-kill-frame'.
 
 * * *
 
@@ -393,6 +400,10 @@
 THINGS TO DO
 ------------
 
+** Search for `suspend-emacs' references and replace them with
+   `suspend-frame', if necessary.  Ditto for `save-buffers-kill-emacs'
+   vs. `save-buffers-kill-display'.
+
 ** Emacs crashes when a tty frame is resized so that there is no space
    for all its windows.  (Tom Schutzer-Weissmann)
 
--- a/lisp/ebuff-menu.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/ebuff-menu.el	Thu Dec 22 21:02:45 2005 +0000
@@ -175,7 +175,7 @@
   (let ((map (make-keymap)))
     (fillarray (car (cdr map)) 'Electric-buffer-menu-undefined)
     (define-key map "\e" nil)
-    (define-key map "\C-z" 'suspend-emacs)
+    (define-key map "\C-z" 'suspend-frame)
     (define-key map "v" 'Electric-buffer-menu-mode-view-buffer)
     (define-key map (char-to-string help-char) 'Helper-help)
     (define-key map "?" 'Helper-describe-bindings)
--- a/lisp/echistory.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/echistory.el	Thu Dec 22 21:02:45 2005 +0000
@@ -65,7 +65,7 @@
   (define-key electric-history-map "\C-c" nil)
   (define-key electric-history-map "\C-c\C-c" 'Electric-history-quit)
   (define-key electric-history-map "\C-]" 'Electric-history-quit)
-  (define-key electric-history-map "\C-z" 'suspend-emacs)
+  (define-key electric-history-map "\C-z" 'suspend-frame)
   (define-key electric-history-map (char-to-string help-char) 'Helper-help)
   (define-key electric-history-map "?" 'Helper-describe-bindings)
   (define-key electric-history-map "\e>" 'end-of-buffer)
--- a/lisp/frame.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/frame.el	Thu Dec 22 21:02:45 2005 +0000
@@ -598,15 +598,18 @@
     (x-initialize-window-system))
   (make-frame `((window-system . x) (display . ,display) . ,parameters)))
 
-(defun make-frame-on-tty (device type &optional parameters)
-  "Make a frame on terminal DEVICE which is of type TYPE (e.g., \"xterm\").
-The optional third argument PARAMETERS specifies additional frame parameters."
+(defun make-frame-on-tty (tty type &optional parameters)
+  "Make a frame on terminal device TTY.
+TTY should be the file name of the tty device to use.  TYPE
+should be the terminal type string of TTY, for example \"xterm\"
+or \"vt100\".  The optional third argument PARAMETERS specifies
+additional frame parameters."
   (interactive "fOpen frame on tty device: \nsTerminal type of %s: ")
-  (unless device
+  (unless tty
     (error "Invalid terminal device"))
   (unless type
     (error "Invalid terminal type"))
-  (make-frame `((window-system . nil) (tty . ,device) (tty-type . ,type) . ,parameters)))
+  (make-frame `((window-system . nil) (tty . ,tty) (tty-type . ,type) . ,parameters)))
 
 (defun make-frame-command ()
   "Make a new frame, and select it if the terminal displays only one frame."
@@ -710,15 +713,15 @@
 		   (eq (frame-display frame) terminal))))
     (filtered-frame-list func)))
 
-(defun framep-on-display (&optional display)
-  "Return the type of frames on DISPLAY.
-DISPLAY may be a display id, a display name or a frame.  If it is
-a frame, its type is returned.
-If DISPLAY is omitted or nil, it defaults to the selected frame's display.
-All frames on a given display are of the same type."
-  (or (display-live-p display)
-      (framep display)
-      (framep (car (frames-on-display-list display)))))
+(defun framep-on-display (&optional terminal)
+  "Return the type of frames on TERMINAL.
+TERMINAL may be a terminal id, a display name or a frame.  If it
+is a frame, its type is returned.  If TERMINAL is omitted or nil,
+it defaults to the selected frame's terminal device.  All frames
+on a given display are of the same type."
+  (or (display-live-p terminal)
+      (framep terminal)
+      (framep (car (frames-on-display-list terminal)))))
 
 (defun frame-remove-geometry-params (param-list)
   "Return the parameter list PARAM-LIST, but with geometry specs removed.
@@ -796,8 +799,8 @@
 
 (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
+Calls `suspend-emacs' if invoked from the controlling tty device,
+`suspend-tty' from a secondary tty device, and
 `iconify-or-deiconify-frame' from an X frame."
   (interactive)
   (let ((type (framep (selected-frame))))
@@ -809,7 +812,6 @@
 	(suspend-tty)))
      (t (suspend-emacs)))))
 
-
 (defun make-frame-names-alist ()
   (let* ((current-frame (selected-frame))
 	 (falist
@@ -1425,146 +1427,6 @@
 (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)
-
-
-(defun terminal-id (terminal)
-  "Return the numerical id of terminal TERMINAL.
-
-TERMINAL can be a terminal id (an integer), a frame, or
-nil (meaning the selected frame's terminal).  Alternatively,
-TERMINAL may be the name of an X display
-device (HOST.SERVER.SCREEN) or a tty device file."
-  (cond
-   ((integerp terminal)
-    (if (display-live-p terminal)
-	terminal
-      (signal 'wrong-type-argument (list 'display-live-p terminal))))
-   ((or (null terminal) (framep terminal))
-    (frame-display terminal))
-   ((stringp terminal)
-    (let ((f (car (filtered-frame-list (lambda (frame)
-					 (or (equal (frame-parameter frame 'display) terminal)
-					     (equal (frame-parameter frame 'tty) terminal)))))))
-      (or f (error "Display %s does not exist" terminal))
-      (frame-display f)))
-   (t
-    (error "Invalid argument %s in `terminal-id'" terminal))))
-
-(defvar terminal-parameter-alist nil
-  "An alist of terminal parameter alists.")
-
-(defun terminal-parameters (&optional terminal)
-  "Return the paramater-alist of terminal TERMINAL.
-It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.
-
-TERMINAL can be a terminal id, a frame, or nil (meaning the
-selected frame's terminal)."
-  (cdr (assq (terminal-id terminal) terminal-parameter-alist)))
-
-(defun terminal-parameter-p (terminal parameter)
-  "Return non-nil if PARAMETER is a terminal parameter on TERMINAL.
-
-The actual value returned in that case is a cell (PARAMETER . VALUE),
-where VALUE is the current value of PARAMETER.
-
-TERMINAL can be a terminal id, a frame, or nil (meaning the
-selected frame's terminal)."
-  (assq parameter (cdr (assq (terminal-id terminal) terminal-parameter-alist))))
-
-(defun terminal-parameter (terminal parameter)
-  "Return TERMINAL's value for parameter PARAMETER.
-
-TERMINAL can be a terminal id, a frame, or nil (meaning the
-selected frame's terminal)."
-  (cdr (terminal-parameter-p terminal parameter)))
-
-(defun set-terminal-parameter (terminal parameter value)
-  "Set TERMINAL's value for parameter PARAMETER to VALUE.
-Returns the previous value of PARAMETER.
-
-TERMINAL can be a terminal id, a frame, or nil (meaning the
-selected frame's terminal)."
-  (setq terminal (terminal-id terminal))
-  (let* ((alist (assq terminal terminal-parameter-alist))
-	 (pair (assq parameter (cdr alist)))
-	 (result (cdr pair)))
-    (cond
-     (pair (setcdr pair value))
-     (alist (setcdr alist (cons (cons parameter value) (cdr alist))))
-     (t (setq terminal-parameter-alist
-	      (cons (cons terminal
-			  (cons (cons parameter value)
-				nil))
-		    terminal-parameter-alist))))
-    result))
-
-(defun terminal-handle-delete-frame (frame)
-  "Clean up terminal parameters of FRAME, if it's the last frame on its terminal."
-  ;; XXX We assume that the display is closed immediately after the
-  ;; last frame is deleted on it.  It would be better to create a hook
-  ;; called `delete-display-functions', and use it instead.
-  (when (and (frame-live-p frame)
-	     (= 1 (length (frames-on-display-list (frame-display frame)))))
-    (setq terminal-parameter-alist
-	  (assq-delete-all (frame-display frame) terminal-parameter-alist))))
-
-(add-hook 'delete-frame-functions 'terminal-handle-delete-frame)
-
-(defun terminal-getenv (variable &optional terminal)
-  "Get the value of VARIABLE in the client environment of TERMINAL.
-VARIABLE should be a string.  Value is nil if VARIABLE is undefined in
-the environment.  Otherwise, value is a string.
-
-If TERMINAL was created by an emacsclient invocation, then the
-variable is looked up in the environment of the emacsclient
-process; otherwise the function consults the environment of the
-Emacs process.
-
-TERMINAL can be a terminal id, a frame, or nil (meaning the
-selected frame's terminal)."
-  (setq terminal (terminal-id terminal))
-  (if (not (terminal-parameter-p terminal 'environment))
-      (getenv variable)
-    (let ((env (terminal-parameter terminal 'environment))
-	  result entry)
-      (while (and env (null result))
-	(setq entry (car env)
-	      env (cdr env))
-	(if (and (> (length entry) (length variable))
-		 (eq ?= (aref entry (length variable)))
-		 (equal variable (substring entry 0 (length variable))))
-	    (setq result (substring entry (+ (length variable) 1)))))
-      (if (null result)
-	  (getenv variable)
-	result))))
-
-(defmacro with-terminal-environment (terminal vars &rest body)
-  "Evaluate BODY with environment variables VARS set to those of TERMINAL.
-The environment variables are then restored to their previous values.
-
-VARS should be a list of strings.
-
-TERMINAL can be a terminal id, a frame, or nil (meaning the
-selected frame's terminal).
-
-See also `terminal-getenv'."
-  (declare (indent 2))
-  (let ((oldvalues (make-symbol "oldvalues"))
-	(var (make-symbol "var"))
-	(value (make-symbol "value"))
-	(pair (make-symbol "pair")))
-    `(let (,oldvalues)
-       (dolist (,var ,vars)
-	 (let ((,value (terminal-getenv ,var ,terminal)))
-	   (setq ,oldvalues (cons (cons ,var (getenv ,var)) ,oldvalues))
-	   (setenv ,var ,value)))
-       (unwind-protect
-	   (progn ,@body)
-	 (dolist (,pair ,oldvalues)
-	   (setenv (car ,pair) (cdr ,pair)))))))
-
-
 (provide 'frame)
 
 ;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56
--- a/lisp/loadup.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/loadup.el	Thu Dec 22 21:02:45 2005 +0000
@@ -132,6 +132,7 @@
 (load "indent")
 (load "window")
 (load "frame")
+(load "termdev")
 (load "term/tty-colors")
 (load "font-core")
 ;; facemenu must be loaded before font-lock, because `facemenu-keymap'
--- a/lisp/progmodes/ebrowse.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/progmodes/ebrowse.el	Thu Dec 22 21:02:45 2005 +0000
@@ -2004,7 +2004,7 @@
     (fillarray (car (cdr map)) 'ebrowse-electric-list-undefined)
     (fillarray (car (cdr submap)) 'ebrowse-electric-list-undefined)
     (define-key map "\e" submap)
-    (define-key map "\C-z" 'suspend-emacs)
+    (define-key map "\C-z" 'suspend-frame)
     (define-key map "\C-h" 'Helper-help)
     (define-key map "?" 'Helper-describe-bindings)
     (define-key map "\C-c" nil)
@@ -3964,7 +3964,7 @@
     (fillarray (car (cdr map)) 'ebrowse-electric-position-undefined)
     (fillarray (car (cdr submap)) 'ebrowse-electric-position-undefined)
     (define-key map "\e" submap)
-    (define-key map "\C-z" 'suspend-emacs)
+    (define-key map "\C-z" 'suspend-frame)
     (define-key map "\C-h" 'Helper-help)
     (define-key map "?" 'Helper-describe-bindings)
     (define-key map "\C-c" nil)
--- a/lisp/startup.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/startup.el	Thu Dec 22 21:02:45 2005 +0000
@@ -1429,7 +1429,7 @@
 	      ;; use precomputed string to save lots of time.
 	      (if (and (eq (key-binding "\C-h") 'help-command)
 		       (eq (key-binding "\C-xu") 'advertised-undo)
-		       (eq (key-binding "\C-x\C-c") 'save-buffers-kill-emacs)
+		       (eq (key-binding "\C-x\C-c") 'save-buffers-kill-display)
 		       (eq (key-binding "\C-ht") 'help-with-tutorial)
 		       (eq (key-binding "\C-hi") 'info)
 		       (eq (key-binding "\C-hr") 'info-emacs-manual)
@@ -1446,7 +1446,7 @@
 Get help	   %s
 Emacs manual	   \\[info-emacs-manual]
 Emacs tutorial	   \\[help-with-tutorial]\tUndo changes\t\\[advertised-undo]
-Buy manuals        \\[view-order-manuals]\tExit Emacs\t\\[save-buffers-kill-emacs]
+Buy manuals        \\[view-order-manuals]\tExit Emacs\t\\[save-buffers-kill-display]
 Browse manuals     \\[info]"
 				 (let ((where (where-is-internal
 					       'help-command nil t)))
--- a/lisp/term/x-win.el	Tue Dec 20 21:35:03 2005 +0000
+++ b/lisp/term/x-win.el	Thu Dec 22 21:02:45 2005 +0000
@@ -2407,7 +2407,7 @@
 	  (aset x-resource-name i ?-))))
 
   (x-open-connection (or x-display-name
-			 (setq x-display-name (terminal-getenv "DISPLAY")))
+			 (setq x-display-name (terminal-getenv "DISPLAY" nil 'global-ok)))
 		     x-command-line-resources
 		     ;; Exit Emacs with fatal error if this fails and we
 		     ;; are the initial display.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/termdev.el	Thu Dec 22 21:02:45 2005 +0000
@@ -0,0 +1,255 @@
+;;; termdev.el --- functions for dealing with terminals
+
+;; Copyright (C) 2005 Free Software Foundation, Inc.
+
+;; Author: Karoly Lorentey <karoly@lorentey.hu>
+;; Created: 2005-12-22
+;; Keywords: internal
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+(substitute-key-definition 'suspend-emacs 'suspend-frame global-map)
+
+(defun terminal-id (terminal)
+  "Return the numerical id of terminal TERMINAL.
+
+TERMINAL can be a terminal id (an integer), a frame, or
+nil (meaning the selected frame's terminal).  Alternatively,
+TERMINAL may be the name of an X display
+device (HOST.SERVER.SCREEN) or a tty device file."
+  (cond
+   ((integerp terminal)
+    (if (display-live-p terminal)
+	terminal
+      (signal 'wrong-type-argument (list 'display-live-p terminal))))
+   ((or (null terminal) (framep terminal))
+    (frame-display terminal))
+   ((stringp terminal)
+    (let ((f (car (filtered-frame-list (lambda (frame)
+					 (or (equal (frame-parameter frame 'display) terminal)
+					     (equal (frame-parameter frame 'tty) terminal)))))))
+      (or f (error "Display %s does not exist" terminal))
+      (frame-display f)))
+   (t
+    (error "Invalid argument %s in `terminal-id'" terminal))))
+
+(defvar terminal-parameter-alist nil
+  "An alist of terminal parameter alists.")
+
+(defun terminal-parameters (&optional terminal)
+  "Return the paramater-alist of terminal TERMINAL.
+It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal)."
+  (cdr (assq (terminal-id terminal) terminal-parameter-alist)))
+
+(defun terminal-parameter-p (terminal parameter)
+  "Return non-nil if PARAMETER is a terminal parameter on TERMINAL.
+
+The actual value returned in that case is a cell (PARAMETER . VALUE),
+where VALUE is the current value of PARAMETER.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal)."
+  (assq parameter (cdr (assq (terminal-id terminal) terminal-parameter-alist))))
+
+(defun terminal-parameter (terminal parameter)
+  "Return TERMINAL's value for parameter PARAMETER.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal)."
+  (cdr (terminal-parameter-p terminal parameter)))
+
+(defun set-terminal-parameter (terminal parameter value)
+  "Set TERMINAL's value for parameter PARAMETER to VALUE.
+Returns the previous value of PARAMETER.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal)."
+  (setq terminal (terminal-id terminal))
+  (let* ((alist (assq terminal terminal-parameter-alist))
+	 (pair (assq parameter (cdr alist)))
+	 (result (cdr pair)))
+    (cond
+     (pair (setcdr pair value))
+     (alist (setcdr alist (cons (cons parameter value) (cdr alist))))
+     (t (setq terminal-parameter-alist
+	      (cons (cons terminal
+			  (cons (cons parameter value)
+				nil))
+		    terminal-parameter-alist))))
+    result))
+
+(defun terminal-handle-delete-frame (frame)
+  "Clean up terminal parameters of FRAME, if it's the last frame on its terminal."
+  ;; XXX We assume that the display is closed immediately after the
+  ;; last frame is deleted on it.  It would be better to create a hook
+  ;; called `delete-display-functions', and use it instead.
+  (when (and (frame-live-p frame)
+	     (= 1 (length (frames-on-display-list (frame-display frame)))))
+    (setq terminal-parameter-alist
+	  (assq-delete-all (frame-display frame) terminal-parameter-alist))))
+
+(add-hook 'delete-frame-functions 'terminal-handle-delete-frame)
+
+(defun terminal-getenv (variable &optional terminal global-ok)
+  "Get the value of VARIABLE in the client environment of TERMINAL.
+VARIABLE should be a string.  Value is nil if VARIABLE is undefined in
+the environment.  Otherwise, value is a string.
+
+If TERMINAL has an associated emacsclient process, then
+`terminal-getenv' looks up VARIABLE in the environment of that
+process; otherwise the function consults the global environment,
+i.e., the environment of the Emacs process itself.
+
+If GLOBAL-OK is non-nil, and VARIABLE is not defined in the
+terminal-local environment, then `terminal-getenv' will return
+its value in the global environment instead.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal)."
+  (setq terminal (terminal-id terminal))
+  (if (not (terminal-parameter-p terminal 'environment))
+      (getenv variable)
+    (if (multibyte-string-p variable)
+	(setq variable (encode-coding-string variable locale-coding-system)))
+    (let ((env (terminal-parameter terminal 'environment))
+	  result entry)
+      (while (and env (null result))
+	(setq entry (car env)
+	      env (cdr env))
+	(if (and (> (length entry) (length variable))
+		 (eq ?= (aref entry (length variable)))
+		 (equal variable (substring entry 0 (length variable))))
+	    (setq result (substring entry (+ (length variable) 1)))))
+      (if (and global-ok (null result))
+	  (getenv variable)
+	(and result (decode-coding-string result locale-coding-system))))))
+
+(defun terminal-setenv (variable &optional value terminal)
+  "Set the value of VARIABLE in the environment of TERMINAL.
+VARIABLE should be string.  VALUE is optional; if not provided or
+nil, the environment variable VARIABLE is removed.  Returned
+value is the new value of VARIABLE, or nil if it was removed from
+the environment.
+
+If TERMINAL was created by an emacsclient invocation, then the
+variable is set in the environment of the emacsclient process;
+otherwise the function changes the environment of the Emacs
+process itself.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal)."
+  (if (not (terminal-parameter-p terminal 'environment))
+      (setenv variable value)
+    (with-terminal-environment terminal variable
+      (setenv variable value))))
+
+(defun terminal-setenv-internal (variable value terminal)
+  "Set the value of VARIABLE in the environment of TERMINAL.
+The caller is responsible to ensure that both VARIABLE and VALUE
+are usable in environment variables and that TERMINAL is a
+remote terminal."
+  (if (multibyte-string-p variable)
+      (setq variable (encode-coding-string variable locale-coding-system)))
+  (if (and value (multibyte-string-p value))
+      (setq value (encode-coding-string value locale-coding-system)))
+  (let ((env (terminal-parameter terminal 'environment))
+	found)
+    (while (and env (not found))
+      (if (and (> (length (car env)) (length variable))
+		 (eq ?= (aref (car env) (length variable)))
+		 (equal variable (substring (car env) 0 (length variable))))
+	  (progn
+	    (if value
+		(setcar env (concat variable "=" value))
+	      (set-terminal-parameter terminal 'environment
+				      (delq (car env)
+					    (terminal-parameter terminal
+								'environment))))
+	    (setq found t))
+	(setq env (cdr env))))
+    (cond
+     ((and value found)
+      (setcar env (concat variable "=" value)))
+     ((and value (not found))
+      (set-terminal-parameter terminal 'environment
+			      (cons (concat variable "=" value)
+				    (terminal-parameter terminal
+							'environment))))
+     ((and (not value) found)
+      (set-terminal-parameter terminal 'environment
+			      (delq (car env)
+				    (terminal-parameter terminal
+							'environment)))))))
+
+(defmacro with-terminal-environment (terminal vars &rest body)
+  "Evaluate BODY with environment variables VARS set to those of TERMINAL.
+The environment variables are then restored to their previous values.
+
+VARS should be a single string, a list of strings, or t for all
+environment variables.
+
+TERMINAL can be a terminal id, a frame, or nil (meaning the
+selected frame's terminal).
+
+If BODY uses `setenv' to change environment variables in VARS,
+then the new variable values will be remembered for TERMINAL, and
+`terminal-getenv' will return them even outside BODY."
+  (declare (indent 2))
+  (let ((var (make-symbol "var"))
+	(term (make-symbol "term"))
+	(v (make-symbol "v"))
+	(old-env (make-symbol "old-env")))
+    `(let ((,term ,terminal)		; Evaluate arguments only once.
+	   (,v ,vars))
+       (if (stringp ,v)
+	   (setq ,v (list ,v)))
+       (cond
+	((not (terminal-parameter-p ,term 'environment))
+	 ;; Not a remote terminal; nothing to do.
+	 (progn ,@body))
+	((eq ,v t)
+	 ;; Switch the entire process-environment.
+	 (let (,old-env process-environment)
+	   (setq process-environment (terminal-parameter ,term 'environment))
+	   (unwind-protect
+	       (progn ,@body)
+	     (set-terminal-parameter ,term 'environment process-environment)
+	     (setq process-environment ,old-env))))
+	(t
+	 ;; Do only a set of variables.
+	 (let (,old-env)
+	   (dolist (,var ,v)
+	     (setq ,old-env (cons (cons ,var (getenv ,var)) ,old-env))
+	     (setenv ,var (terminal-getenv ,var ,term)))
+	   (unwind-protect
+	       (progn ,@body)
+	     ;; Split storing new values and restoring old ones so
+	     ;; that we DTRT even if a variable is specified twice in
+	     ;; VARS.
+	     (dolist (,var ,v)
+	       (terminal-setenv-internal ,var (getenv ,var) ,term))
+	     (dolist (,var ,old-env)
+	       (setenv (car ,var) (cdr ,var))))))))))
+
+(provide 'termdev)
+
+;;; arch-tag: 4c4df277-1ec1-4f56-bfde-7f156fe62fb2
+;;; termdev.el ends here
--- a/mac/makefile.MPW	Tue Dec 20 21:35:03 2005 +0000
+++ b/mac/makefile.MPW	Thu Dec 22 21:02:45 2005 +0000
@@ -1021,6 +1021,7 @@
 	{Lisp}emacs-lisp:float-sup.elc ¶
 	{Lisp}format.elc ¶
 	{Lisp}frame.elc ¶
+	{Lisp}termdev.elc ¶
 	{Lisp}help.elc ¶
 	{Lisp}indent.elc ¶
 	{Lisp}isearch.elc ¶
--- a/src/Makefile.in	Tue Dec 20 21:35:03 2005 +0000
+++ b/src/Makefile.in	Thu Dec 22 21:02:45 2005 +0000
@@ -722,6 +722,7 @@
 	MOUSE_SUPPORT \
 	${lispsource}emacs-lisp/float-sup.elc \
 	${lispsource}frame.elc \
+	${lispsource}termdev.elc \
 	${lispsource}help.elc \
 	${lispsource}indent.elc \
 	${lispsource}isearch.elc \
@@ -819,6 +820,7 @@
 	../lisp/emacs-lisp/float-sup.elc \
 	../lisp/format.elc \
 	../lisp/frame.elc \
+	../lisp/termdev.elc \
 	../lisp/help.elc \
 	../lisp/indent.elc \
 	../lisp/isearch.elc \
--- a/src/print.c	Tue Dec 20 21:35:03 2005 +0000
+++ b/src/print.c	Thu Dec 22 21:02:45 2005 +0000
@@ -1343,7 +1343,7 @@
 	  for (i = 0; i < print_number_index; i++)
 	    if (EQ (PRINT_NUMBER_OBJECT (Vprint_number_table, i), obj))
 	      {
-		/* OBJ appears more than once.  Let's remember that.  */
+		/* OBJ appears more than once.	Let's remember that.  */
 		PRINT_NUMBER_STATUS (Vprint_number_table, i) = Qt;
 		return;
 	      }
--- a/src/term.c	Tue Dec 20 21:35:03 2005 +0000
+++ b/src/term.c	Thu Dec 22 21:02:45 2005 +0000
@@ -3270,23 +3270,23 @@
 
 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 ceases 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 be a display id, a frame, or nil for the display device of the
-currently selected frame.
+
+The device is restored to its default state, and Emacs ceases all
+access to the tty 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 be a terminal id, a frame, or nil for the terminal device of
+the currently selected frame.
 
 This function runs `suspend-tty-functions' after suspending the
 device.  The functions are run with one arg, the id of the suspended
-display 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. */)
+terminal device.
+
+`suspend-tty' does nothing if it is called on a device that is already
+suspended.
+
+A suspended tty may be resumed by calling `resume-tty' on it.  */)
   (tty)
      Lisp_Object tty;
 {