diff lisp/termdev.el @ 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
children 521d3f18b3d1
line wrap: on
line diff
--- /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