Mercurial > emacs
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 83415:d2c799f58129 | 83416:4513d8dcdfd5 |
|---|---|
| 1 ;;; termdev.el --- functions for dealing with terminals | |
| 2 | |
| 3 ;; Copyright (C) 2005 Free Software Foundation, Inc. | |
| 4 | |
| 5 ;; Author: Karoly Lorentey <karoly@lorentey.hu> | |
| 6 ;; Created: 2005-12-22 | |
| 7 ;; Keywords: internal | |
| 8 | |
| 9 ;; This file is part of GNU Emacs. | |
| 10 | |
| 11 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
| 12 ;; it under the terms of the GNU General Public License as published by | |
| 13 ;; the Free Software Foundation; either version 2, or (at your option) | |
| 14 ;; any later version. | |
| 15 | |
| 16 ;; GNU Emacs is distributed in the hope that it will be useful, | |
| 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 ;; GNU General Public License for more details. | |
| 20 | |
| 21 ;; You should have received a copy of the GNU General Public License | |
| 22 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
| 23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 24 ;; Boston, MA 02110-1301, USA. | |
| 25 | |
| 26 (substitute-key-definition 'suspend-emacs 'suspend-frame global-map) | |
| 27 | |
| 28 (defun terminal-id (terminal) | |
| 29 "Return the numerical id of terminal TERMINAL. | |
| 30 | |
| 31 TERMINAL can be a terminal id (an integer), a frame, or | |
| 32 nil (meaning the selected frame's terminal). Alternatively, | |
| 33 TERMINAL may be the name of an X display | |
| 34 device (HOST.SERVER.SCREEN) or a tty device file." | |
| 35 (cond | |
| 36 ((integerp terminal) | |
| 37 (if (display-live-p terminal) | |
| 38 terminal | |
| 39 (signal 'wrong-type-argument (list 'display-live-p terminal)))) | |
| 40 ((or (null terminal) (framep terminal)) | |
| 41 (frame-display terminal)) | |
| 42 ((stringp terminal) | |
| 43 (let ((f (car (filtered-frame-list (lambda (frame) | |
| 44 (or (equal (frame-parameter frame 'display) terminal) | |
| 45 (equal (frame-parameter frame 'tty) terminal))))))) | |
| 46 (or f (error "Display %s does not exist" terminal)) | |
| 47 (frame-display f))) | |
| 48 (t | |
| 49 (error "Invalid argument %s in `terminal-id'" terminal)))) | |
| 50 | |
| 51 (defvar terminal-parameter-alist nil | |
| 52 "An alist of terminal parameter alists.") | |
| 53 | |
| 54 (defun terminal-parameters (&optional terminal) | |
| 55 "Return the paramater-alist of terminal TERMINAL. | |
| 56 It is a list of elements of the form (PARM . VALUE), where PARM is a symbol. | |
| 57 | |
| 58 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 59 selected frame's terminal)." | |
| 60 (cdr (assq (terminal-id terminal) terminal-parameter-alist))) | |
| 61 | |
| 62 (defun terminal-parameter-p (terminal parameter) | |
| 63 "Return non-nil if PARAMETER is a terminal parameter on TERMINAL. | |
| 64 | |
| 65 The actual value returned in that case is a cell (PARAMETER . VALUE), | |
| 66 where VALUE is the current value of PARAMETER. | |
| 67 | |
| 68 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 69 selected frame's terminal)." | |
| 70 (assq parameter (cdr (assq (terminal-id terminal) terminal-parameter-alist)))) | |
| 71 | |
| 72 (defun terminal-parameter (terminal parameter) | |
| 73 "Return TERMINAL's value for parameter PARAMETER. | |
| 74 | |
| 75 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 76 selected frame's terminal)." | |
| 77 (cdr (terminal-parameter-p terminal parameter))) | |
| 78 | |
| 79 (defun set-terminal-parameter (terminal parameter value) | |
| 80 "Set TERMINAL's value for parameter PARAMETER to VALUE. | |
| 81 Returns the previous value of PARAMETER. | |
| 82 | |
| 83 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 84 selected frame's terminal)." | |
| 85 (setq terminal (terminal-id terminal)) | |
| 86 (let* ((alist (assq terminal terminal-parameter-alist)) | |
| 87 (pair (assq parameter (cdr alist))) | |
| 88 (result (cdr pair))) | |
| 89 (cond | |
| 90 (pair (setcdr pair value)) | |
| 91 (alist (setcdr alist (cons (cons parameter value) (cdr alist)))) | |
| 92 (t (setq terminal-parameter-alist | |
| 93 (cons (cons terminal | |
| 94 (cons (cons parameter value) | |
| 95 nil)) | |
| 96 terminal-parameter-alist)))) | |
| 97 result)) | |
| 98 | |
| 99 (defun terminal-handle-delete-frame (frame) | |
| 100 "Clean up terminal parameters of FRAME, if it's the last frame on its terminal." | |
| 101 ;; XXX We assume that the display is closed immediately after the | |
| 102 ;; last frame is deleted on it. It would be better to create a hook | |
| 103 ;; called `delete-display-functions', and use it instead. | |
| 104 (when (and (frame-live-p frame) | |
| 105 (= 1 (length (frames-on-display-list (frame-display frame))))) | |
| 106 (setq terminal-parameter-alist | |
| 107 (assq-delete-all (frame-display frame) terminal-parameter-alist)))) | |
| 108 | |
| 109 (add-hook 'delete-frame-functions 'terminal-handle-delete-frame) | |
| 110 | |
| 111 (defun terminal-getenv (variable &optional terminal global-ok) | |
| 112 "Get the value of VARIABLE in the client environment of TERMINAL. | |
| 113 VARIABLE should be a string. Value is nil if VARIABLE is undefined in | |
| 114 the environment. Otherwise, value is a string. | |
| 115 | |
| 116 If TERMINAL has an associated emacsclient process, then | |
| 117 `terminal-getenv' looks up VARIABLE in the environment of that | |
| 118 process; otherwise the function consults the global environment, | |
| 119 i.e., the environment of the Emacs process itself. | |
| 120 | |
| 121 If GLOBAL-OK is non-nil, and VARIABLE is not defined in the | |
| 122 terminal-local environment, then `terminal-getenv' will return | |
| 123 its value in the global environment instead. | |
| 124 | |
| 125 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 126 selected frame's terminal)." | |
| 127 (setq terminal (terminal-id terminal)) | |
| 128 (if (not (terminal-parameter-p terminal 'environment)) | |
| 129 (getenv variable) | |
| 130 (if (multibyte-string-p variable) | |
| 131 (setq variable (encode-coding-string variable locale-coding-system))) | |
| 132 (let ((env (terminal-parameter terminal 'environment)) | |
| 133 result entry) | |
| 134 (while (and env (null result)) | |
| 135 (setq entry (car env) | |
| 136 env (cdr env)) | |
| 137 (if (and (> (length entry) (length variable)) | |
| 138 (eq ?= (aref entry (length variable))) | |
| 139 (equal variable (substring entry 0 (length variable)))) | |
| 140 (setq result (substring entry (+ (length variable) 1))))) | |
| 141 (if (and global-ok (null result)) | |
| 142 (getenv variable) | |
| 143 (and result (decode-coding-string result locale-coding-system)))))) | |
| 144 | |
| 145 (defun terminal-setenv (variable &optional value terminal) | |
| 146 "Set the value of VARIABLE in the environment of TERMINAL. | |
| 147 VARIABLE should be string. VALUE is optional; if not provided or | |
| 148 nil, the environment variable VARIABLE is removed. Returned | |
| 149 value is the new value of VARIABLE, or nil if it was removed from | |
| 150 the environment. | |
| 151 | |
| 152 If TERMINAL was created by an emacsclient invocation, then the | |
| 153 variable is set in the environment of the emacsclient process; | |
| 154 otherwise the function changes the environment of the Emacs | |
| 155 process itself. | |
| 156 | |
| 157 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 158 selected frame's terminal)." | |
| 159 (if (not (terminal-parameter-p terminal 'environment)) | |
| 160 (setenv variable value) | |
| 161 (with-terminal-environment terminal variable | |
| 162 (setenv variable value)))) | |
| 163 | |
| 164 (defun terminal-setenv-internal (variable value terminal) | |
| 165 "Set the value of VARIABLE in the environment of TERMINAL. | |
| 166 The caller is responsible to ensure that both VARIABLE and VALUE | |
| 167 are usable in environment variables and that TERMINAL is a | |
| 168 remote terminal." | |
| 169 (if (multibyte-string-p variable) | |
| 170 (setq variable (encode-coding-string variable locale-coding-system))) | |
| 171 (if (and value (multibyte-string-p value)) | |
| 172 (setq value (encode-coding-string value locale-coding-system))) | |
| 173 (let ((env (terminal-parameter terminal 'environment)) | |
| 174 found) | |
| 175 (while (and env (not found)) | |
| 176 (if (and (> (length (car env)) (length variable)) | |
| 177 (eq ?= (aref (car env) (length variable))) | |
| 178 (equal variable (substring (car env) 0 (length variable)))) | |
| 179 (progn | |
| 180 (if value | |
| 181 (setcar env (concat variable "=" value)) | |
| 182 (set-terminal-parameter terminal 'environment | |
| 183 (delq (car env) | |
| 184 (terminal-parameter terminal | |
| 185 'environment)))) | |
| 186 (setq found t)) | |
| 187 (setq env (cdr env)))) | |
| 188 (cond | |
| 189 ((and value found) | |
| 190 (setcar env (concat variable "=" value))) | |
| 191 ((and value (not found)) | |
| 192 (set-terminal-parameter terminal 'environment | |
| 193 (cons (concat variable "=" value) | |
| 194 (terminal-parameter terminal | |
| 195 'environment)))) | |
| 196 ((and (not value) found) | |
| 197 (set-terminal-parameter terminal 'environment | |
| 198 (delq (car env) | |
| 199 (terminal-parameter terminal | |
| 200 'environment))))))) | |
| 201 | |
| 202 (defmacro with-terminal-environment (terminal vars &rest body) | |
| 203 "Evaluate BODY with environment variables VARS set to those of TERMINAL. | |
| 204 The environment variables are then restored to their previous values. | |
| 205 | |
| 206 VARS should be a single string, a list of strings, or t for all | |
| 207 environment variables. | |
| 208 | |
| 209 TERMINAL can be a terminal id, a frame, or nil (meaning the | |
| 210 selected frame's terminal). | |
| 211 | |
| 212 If BODY uses `setenv' to change environment variables in VARS, | |
| 213 then the new variable values will be remembered for TERMINAL, and | |
| 214 `terminal-getenv' will return them even outside BODY." | |
| 215 (declare (indent 2)) | |
| 216 (let ((var (make-symbol "var")) | |
| 217 (term (make-symbol "term")) | |
| 218 (v (make-symbol "v")) | |
| 219 (old-env (make-symbol "old-env"))) | |
| 220 `(let ((,term ,terminal) ; Evaluate arguments only once. | |
| 221 (,v ,vars)) | |
| 222 (if (stringp ,v) | |
| 223 (setq ,v (list ,v))) | |
| 224 (cond | |
| 225 ((not (terminal-parameter-p ,term 'environment)) | |
| 226 ;; Not a remote terminal; nothing to do. | |
| 227 (progn ,@body)) | |
| 228 ((eq ,v t) | |
| 229 ;; Switch the entire process-environment. | |
| 230 (let (,old-env process-environment) | |
| 231 (setq process-environment (terminal-parameter ,term 'environment)) | |
| 232 (unwind-protect | |
| 233 (progn ,@body) | |
| 234 (set-terminal-parameter ,term 'environment process-environment) | |
| 235 (setq process-environment ,old-env)))) | |
| 236 (t | |
| 237 ;; Do only a set of variables. | |
| 238 (let (,old-env) | |
| 239 (dolist (,var ,v) | |
| 240 (setq ,old-env (cons (cons ,var (getenv ,var)) ,old-env)) | |
| 241 (setenv ,var (terminal-getenv ,var ,term))) | |
| 242 (unwind-protect | |
| 243 (progn ,@body) | |
| 244 ;; Split storing new values and restoring old ones so | |
| 245 ;; that we DTRT even if a variable is specified twice in | |
| 246 ;; VARS. | |
| 247 (dolist (,var ,v) | |
| 248 (terminal-setenv-internal ,var (getenv ,var) ,term)) | |
| 249 (dolist (,var ,old-env) | |
| 250 (setenv (car ,var) (cdr ,var)))))))))) | |
| 251 | |
| 252 (provide 'termdev) | |
| 253 | |
| 254 ;;; arch-tag: 4c4df277-1ec1-4f56-bfde-7f156fe62fb2 | |
| 255 ;;; termdev.el ends here |
