changeset 83427:2afc49c9f0c0

Store local environment in frame (not terminal) parameters. * src/callproc.c (child_setup, getenv_internal, Fgetenv_internal): Store the local environment in a frame (not terminal) parameter. Update doc strings. (syms_of_callproc): Update doc strings. (Qenvironment): Moved to frame.c. * lisp/env.el (read-envvar-name, setenv, getenv, environment): Use frame parameters to store the local environment, not terminal parameters. * server.el (server-process-filter): Store the local environment in a frame (not terminal) parameter. Do not try to decode environment strings. * lisp/frame.el (make-frame): Set up the 'environment frame parameter, when needed. * src/frame.c (Qenvironment): Move here from callproc.c. (Fdelete_frame): Don't allow other frames to refer to a deleted frame in their 'environment parameter. (Fframe_with_environment): New function. (syms_of_frame): Defsubr it. Initialize and staticpro Qenvironment. * frame.h (Qenvironment): Declare. * lisp.h (Fframe_with_environment): EXFUN it. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-467
author Karoly Lorentey <lorentey@elte.hu>
date Thu, 29 Dec 2005 04:31:04 +0000
parents 7c7d1f1cb2e7
children d0eee3282e6b
files README.multi-tty lisp/env.el lisp/frame.el lisp/server.el src/callproc.c src/frame.c src/frame.h src/lisp.h
diffstat 8 files changed, 167 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/README.multi-tty	Thu Dec 29 02:10:23 2005 +0000
+++ b/README.multi-tty	Thu Dec 29 04:31:04 2005 +0000
@@ -412,7 +412,10 @@
 
    	make_terminal_frame
 		create_tty_output
-	
+
+** Decide whether to keep the C implementation of terminal parameters,
+   or revert to the previous, purely Lisp code.  It turned out that
+   local environments do not need terminal parameters after all.
 
 ** Move Fsend_string_to_terminal to term.c, and declare get_named_tty
    as static, removing it from dispextern.h.
@@ -1362,5 +1365,16 @@
    `getenv' and `setenv', and the new `local-environment-variables'
    facility.  Yay!)
 
+   (Updated in patch-465 to fix the semantics of let-binding
+   `process-environment'.  `process-environment' was changed to
+   override all local/global environment variables, and a new variable
+   `global-environment' was introduced to have `process-environment's
+   old meaning.)
+
+   (Updated in patch-466 to fix the case when two emacsclient sessions
+   share the same terminal, but have different environment.  The local
+   environment lists are now stored as frame parameters, so the
+   C-level terminal parameters are not strictly necessary any more.)
+
 ;;; arch-tag: 8da1619e-2e79-41a8-9ac9-a0485daad17d
 
--- a/lisp/env.el	Thu Dec 29 02:10:23 2005 +0000
+++ b/lisp/env.el	Thu Dec 29 04:31:04 2005 +0000
@@ -55,7 +55,7 @@
 				     (substring enventry 0
 						(string-match "=" enventry)))))
 			   (append process-environment
-				   (terminal-parameter nil 'environment)
+				   (frame-parameter (frame-with-environment) 'environment)
 				   global-environment))
 		   nil mustmatch nil 'read-envvar-name-history))
 
@@ -94,7 +94,7 @@
 
 ;; Fixme: Should the environment be recoded if LC_CTYPE &c is set?
 
-(defun setenv (variable &optional value unset substitute-env-vars terminal)
+(defun setenv (variable &optional value unset substitute-env-vars frame)
   "Set the value of the environment variable named VARIABLE to VALUE.
 VARIABLE should be a string.  VALUE is optional; if not provided or
 nil, the environment variable VARIABLE will be removed.  UNSET
@@ -112,12 +112,15 @@
 If VARIABLE is set in `process-environment', then this function
 modifies its value there.  Otherwise, this function works by
 modifying either `global-environment' or the environment
-belonging to the terminal device of the selected frame, depending
-on the value of `local-environment-variables'.
+belonging to the selected frame, depending on the value of
+`local-environment-variables'.
 
-If optional parameter TERMINAL is non-nil, then it should be a
-terminal id or a frame.  If the specified terminal device has its own
-set of environment variables, this function will modify VAR in it.
+If optional parameter FRAME is non-nil, then it should be a a
+frame.  If the specified frame has its own set of environment
+variables, this function will modify VARIABLE in it.  Note that
+frames on the same terminal device usually share their
+environment, so calling `setenv' on one of them affects the
+others as well.
 
 As a special case, setting variable `TZ' calls `set-time-zone-rule' as
 a side-effect."
@@ -153,9 +156,11 @@
       (error "Environment variable name `%s' contains `='" variable))
   (let ((pattern (concat "\\`" (regexp-quote variable) "\\(=\\|\\'\\)"))
 	(case-fold-search nil)
-	(terminal-env (terminal-parameter terminal 'environment))
+	(frame-env (frame-parameter (frame-with-environment frame) 'environment))
+	(frame-forced (not frame))
 	(scan process-environment)
 	found)
+    (setq frame (frame-with-environment frame))
     (if (string-equal "TZ" variable)
 	(set-time-zone-rule value))
     (block nil
@@ -166,55 +171,54 @@
 	      (setcar scan (concat variable "=" value))
 	    ;; Leave unset variables in `process-environment',
 	    ;; otherwise the overridden value in `global-environment'
-	    ;; or terminal-env would become unmasked.
+	    ;; or frame-env would become unmasked.
 	    (setcar scan variable))
 	  (return value))
 	(setq scan (cdr scan)))
 
       ;; Look in the local or global environment, whichever is relevant.
-      (let ((local-var-p (and terminal-env
-			      (or terminal
+      (let ((local-var-p (and frame-env
+			      (or frame-forced
 				  (eq t local-environment-variables)
 				  (member variable local-environment-variables)))))
 	(setq scan (if local-var-p
-		       terminal-env
+		       frame-env
 		     global-environment))
 	(while scan
 	  (when (string-match pattern (car scan))
 	    (if value
 		(setcar scan (concat variable "=" value))
 	      (if local-var-p
-		  (set-terminal-parameter terminal 'environment
-					  (delq (car scan) terminal-env))
-		(setq global-environment (delq (car scan) global-environment)))
-	      (return value)))
+		  (set-frame-parameter frame 'environment
+				       (delq (car scan) frame-env))
+		(setq global-environment (delq (car scan) global-environment))))
+	    (return value))
 	  (setq scan (cdr scan)))
 
 	;; VARIABLE is not in any environment list.
 	(if value
 	    (if local-var-p
-		(set-terminal-parameter nil 'environment
-					(cons (concat variable "=" value)
-					      terminal-env))
+		(set-frame-parameter frame 'environment
+				     (cons (concat variable "=" value)
+					   frame-env))
 	      (setq global-environment
 		    (cons (concat variable "=" value)
 			  global-environment))))
 	(return value)))))
 
-(defun getenv (variable &optional terminal)
+(defun getenv (variable &optional frame)
   "Get the value of environment variable VARIABLE.
 VARIABLE should be a string.  Value is nil if VARIABLE is undefined in
 the environment.  Otherwise, value is a string.
 
-If optional parameter TERMINAL is non-nil, then it should be a
-terminal id or a frame.  If the specified terminal device has its own
-set of environment variables, this function will look up VARIABLE in
-it.
+If optional parameter FRAME is non-nil, then it should be a
+frame.  If the specified terminal device has its own set of
+environment variables, this function will look up VARIABLE in it.
 
-Otherwise, this function searches `process-environment' for VARIABLE.
-If it was not found there, then it continues the search in either
-`global-environment' or the local environment list of the current
-terminal device, depending on the value of
+Otherwise, this function searches `process-environment' for
+VARIABLE.  If it was not found there, then it continues the
+search in either `global-environment' or the environment list of
+the selected frame, depending on the value of
 `local-environment-variables'."
   (interactive (list (read-envvar-name "Get environment variable: " t)))
   (let ((value (getenv-internal (if (multibyte-string-p variable)
@@ -236,21 +240,23 @@
 
 The list is constructed from elements of `process-environment',
 `global-environment' and the local environment list of the
-current terminal, as specified by `local-environment-variables'.
+selected frame, as specified by `local-environment-variables'.
 
 Non-ASCII characters are encoded according to the initial value of
 `locale-coding-system', i.e. the elements must normally be decoded for use.
 See `setenv' and `getenv'."
-  (let ((env (cond ((or (not local-environment-variables)
-			(not (terminal-parameter nil 'environment)))
-		    (append process-environment global-environment nil))
-		   ((consp local-environment-variables)
-		    (let ((e (reverse process-environment)))
-		      (dolist (entry local-environment-variables)
-			(setq e (cons (getenv entry) e)))
-		      (append (nreverse e) global-environment nil)))
-		   (t
-		    (append process-environment (terminal-parameter nil 'environment) nil))))
+  (let ((env (let ((local-env (frame-parameter (frame-with-environment)
+					       'environment)))
+	       (cond ((or (not local-environment-variables)
+			  (not local-env))
+		      (append process-environment global-environment nil))
+		     ((consp local-environment-variables)
+		      (let ((e (reverse process-environment)))
+			(dolist (entry local-environment-variables)
+			  (setq e (cons (getenv entry) e)))
+			(append (nreverse e) global-environment nil)))
+		     (t
+		      (append process-environment local-env nil)))))
 	scan seen)
     ;; Find the first valid entry in env.
     (while (and env (stringp (car env))
--- a/lisp/frame.el	Thu Dec 29 02:10:23 2005 +0000
+++ b/lisp/frame.el	Thu Dec 29 04:31:04 2005 +0000
@@ -674,12 +674,20 @@
 	      (cdr (assq 'window-system parameters)))
 	     (t window-system)))
 	 (frame-creation-function (cdr (assq w frame-creation-function-alist)))
+	 (oldframe (selected-frame))
 	 frame)
     (unless frame-creation-function
       (error "Don't know how to create a frame on window system %s" w))
     (run-hooks 'before-make-frame-hook)
     (setq frame (funcall frame-creation-function (append parameters (cdr (assq w window-system-default-frame-alist)))))
     (normal-erase-is-backspace-setup-frame frame)
+    ;; Set up the frame-local environment, if needed.
+    (when (eq (frame-display frame) (frame-display oldframe))
+      (let ((env (frame-parameter oldframe 'environment)))
+	(if (not (framep env))
+	    (setq env oldframe))
+	(if env
+	    (set-frame-parameter frame 'environment env))))
     (run-hook-with-args 'after-make-frame-functions frame)
     frame))
 
--- a/lisp/server.el	Thu Dec 29 02:10:23 2005 +0000
+++ b/lisp/server.el	Thu Dec 29 04:31:04 2005 +0000
@@ -620,8 +620,8 @@
 					  ;; emacsclient quits while also preventing
 					  ;; `server-save-buffers-kill-display' from unexpectedly
 					  ;; killing emacs on that frame.
-					  (list (cons 'client 'nowait))
-					(list (cons 'client proc)))))
+					  (list (cons 'client 'nowait) (cons 'environment env))
+					(list (cons 'client proc) (cons 'environment env)))))
 			  (setq frame (make-frame-on-display
 				       (or display
 					   (frame-parameter nil 'display)
@@ -637,7 +637,6 @@
 			  (select-frame frame)
 			  (server-client-set client 'frame frame)
 			  (server-client-set client 'device (frame-display frame))
-			  (set-terminal-parameter frame 'environment env)
 			  (setq dontkill t))
 		      ;; This emacs does not support X.
 		      (server-log "Window system unsupported" proc)
@@ -684,12 +683,12 @@
 			(setq frame (make-frame-on-tty tty type
 						       ;; Ignore nowait here; we always need to clean
 						       ;; up opened ttys when the client dies.
-						       `((client . ,proc)))))
+						       `((client . ,proc)
+							 (environment . ,env)))))
 		      (select-frame frame)
 		      (server-client-set client 'frame frame)
 		      (server-client-set client 'tty (display-name frame))
 		      (server-client-set client 'device (frame-display frame))
-		      (set-terminal-parameter frame 'environment env)
 
 		      ;; Reply with our pid.
 		      (server-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n"))
@@ -740,8 +739,7 @@
 		 ;; -env NAME=VALUE:  An environment variable.
 		 ((and (equal "-env" arg) (string-match "\\([^ ]+\\) " request))
 		  (let ((var (server-unquote-arg (match-string 1 request))))
-		    (when coding-system
-		      (setq var (decode-coding-string var coding-system)))
+		    ;; XXX Variables should be encoded as in getenv/setenv.
 		    (setq request (substring request (match-end 0)))
 		    (setq env (cons var env))))
 
--- a/src/callproc.c	Thu Dec 29 02:10:23 2005 +0000
+++ b/src/callproc.c	Thu Dec 29 04:31:04 2005 +0000
@@ -119,7 +119,6 @@
 #ifdef DOS_NT
 Lisp_Object Qbuffer_file_type;
 #endif /* DOS_NT */
-Lisp_Object Qenvironment;
 
 /* True iff we are about to fork off a synchronous process or if we
    are waiting for it.  */
@@ -1319,8 +1318,8 @@
 
     if (!NILP (Vlocal_environment_variables))
       {
-        local = get_terminal_param (FRAME_DEVICE (XFRAME (selected_frame)),
-                                    Qenvironment);
+        local = get_frame_param (XFRAME (Fframe_with_environment (selected_frame)),
+                                 Qenvironment);
         if (EQ (Vlocal_environment_variables, Qt)
             && !NILP (local))
           environment = local;
@@ -1356,7 +1355,7 @@
       new_env = add_env (env, new_env, egetenv (SDATA (XCAR (tem))));
 
     /* The rest of the environment (either Vglobal_environment or the
-       'environment terminal parameter).  */
+       'environment frame parameter).  */
     for (tem = environment;
 	 CONSP (tem) && STRINGP (XCAR (tem));
 	 tem = XCDR (tem))
@@ -1488,12 +1487,12 @@
 }
 
 static int
-getenv_internal (var, varlen, value, valuelen, terminal)
+getenv_internal (var, varlen, value, valuelen, frame)
      char *var;
      int varlen;
      char **value;
      int *valuelen;
-     Lisp_Object terminal;
+     Lisp_Object frame;
 {
   Lisp_Object scan;
   Lisp_Object environment = Vglobal_environment;
@@ -1528,17 +1527,19 @@
     }
 
   /* Find the environment in which to search the variable. */
-  if (!NILP (terminal))
+  if (!NILP (frame))
     {
-      Lisp_Object local = get_terminal_param (get_device (terminal, 1), Qenvironment);
+      CHECK_FRAME (frame);
+      frame = Fframe_with_environment (frame);
+      Lisp_Object local = get_frame_param (XFRAME (frame), Qenvironment);
       /* Use Vglobal_environment if there is no local environment.  */
       if (!NILP (local))
         environment = local;
     }
   else if (!NILP (Vlocal_environment_variables)) 
     {
-      Lisp_Object local = get_terminal_param (FRAME_DEVICE (XFRAME (selected_frame)),
-                                              Qenvironment);
+      Lisp_Object local = get_frame_param (XFRAME (Fframe_with_environment (selected_frame)),
+                                           Qenvironment);
       if (EQ (Vlocal_environment_variables, Qt)
           && !NILP (local))
         environment = local;
@@ -1594,25 +1595,23 @@
 VARIABLE should be a string.  Value is nil if VARIABLE is undefined in
 the environment.  Otherwise, value is a string.
 
-If optional parameter TERMINAL is non-nil, then it should be a
-terminal id or a frame.  If the specified terminal device has its own
-set of environment variables, this function will look up VARIABLE in
-it.
+If optional parameter FRAME is non-nil, then it should be a frame.  If
+that frame has its own set of environment variables, this function
+will look up VARIABLE in there.
 
 Otherwise, this function searches `process-environment' for VARIABLE.
 If it was not found there, then it continues the search in either
 `global-environment' or the local environment list of the current
-terminal device, depending on the value of
-`local-environment-variables'.  */)
-     (variable, terminal)
-     Lisp_Object variable, terminal;
+frame, depending on the value of `local-environment-variables'.  */)
+     (variable, frame)
+     Lisp_Object variable, frame;
 {
   char *value;
   int valuelen;
 
   CHECK_STRING (variable);
   if (getenv_internal (SDATA (variable), SBYTES (variable),
-		       &value, &valuelen, terminal))
+		       &value, &valuelen, frame))
     return make_string (value, valuelen);
   else
     return Qnil;
@@ -1842,11 +1841,10 @@
 The environment which Emacs inherits is placed in this variable when
 Emacs starts.
 
-Some terminal devices may have their own local list of environment
-variables in their 'environment parameter, which may override this
-global list; see `local-environment-variables'.  See
-`process-environment' for a way to modify an environment variable on
-all terminals.
+Some frames may have their own local list of environment variables in
+their 'environment parameter, which may override this global list; see
+`local-environment-variables'.  See `process-environment' for a way to
+modify an environment variable on all frames.
 
 If multiple entries define the same variable, the first one always
 takes precedence.
@@ -1860,12 +1858,12 @@
 Each element should be a string of the form ENVVARNAME=VALUE.
 
 Entries in this list take precedence to those in `global-environment'
-or the terminal environment.  (See `local-environment-variables' for
-an explanation of the terminal-local environment.)  Therefore,
-let-binding `process-environment' is an easy way to temporarily change
-the value of an environment variable, irrespective of where it comes
-from.  To use `process-environment' to remove an environment variable,
-include only its name in the list, without "=VALUE".
+or the frame-local environment.  (See `local-environment-variables'.)
+Therefore, let-binding `process-environment' is an easy way to
+temporarily change the value of an environment variable, irrespective
+of where it comes from.  To use `process-environment' to remove an
+environment variable, include only its name in the list, without
+"=VALUE".
 
 This variable is set to nil when Emacs starts.
 
@@ -1886,21 +1884,18 @@
   defsubr (&Scall_process_region);
 
   DEFVAR_LISP ("local-environment-variables", &Vlocal_environment_variables,
-               doc: /* 	Enable or disable terminal-local environment variables.
+               doc: /* 	Enable or disable frame-local environment variables.
 If set to t, `getenv', `setenv' and subprocess creation functions use
-the local environment of the terminal device of the selected frame,
-ignoring `global-environment'.
+the local environment of the selected frame, ignoring
+`global-environment'.
 
 If set to nil, Emacs uses `global-environment' and ignores the
-terminal environment.
+frame-local environment.
 
 Otherwise, `local-environment-variables' should be a list of variable
-names (represented by Lisp strings) to look up in the terminal's
+names (represented by Lisp strings) to look up in the frame's
 environment.  The rest will come from `global-environment'.  */);
   Vlocal_environment_variables = Qnil;
-
-  Qenvironment = intern ("environment");
-  staticpro (&Qenvironment);
 }
 
 /* arch-tag: 769b8045-1df7-4d2b-8968-e3fb49017f95
--- a/src/frame.c	Thu Dec 29 02:10:23 2005 +0000
+++ b/src/frame.c	Thu Dec 29 04:31:04 2005 +0000
@@ -111,6 +111,7 @@
 Lisp_Object Qtty_color_mode;
 Lisp_Object Qtty, Qtty_type;
 Lisp_Object Qwindow_system;
+Lisp_Object Qenvironment;
 
 Lisp_Object Qfullscreen, Qfullwidth, Qfullheight, Qfullboth;
 
@@ -1473,6 +1474,24 @@
   if (EQ (f->minibuffer_window, echo_area_window))
     echo_area_window = sf->minibuffer_window;
 
+  /* Don't allow other frames to refer to a deleted frame in their
+     'environment parameter.  */
+  {
+    Lisp_Object tail, frame1;
+    Lisp_Object env = get_frame_param (XFRAME (frame), Qenvironment);
+    FOR_EACH_FRAME (tail, frame1)
+      {
+        if (EQ (frame, frame1) || !FRAME_LIVE_P (XFRAME (frame1)))
+          continue;
+        if (EQ (frame, get_frame_param (XFRAME (frame1), Qenvironment)))
+          {
+            store_frame_param (XFRAME (frame1), Qenvironment, env);
+            if (!FRAMEP (env))
+              env = frame1;
+          }
+      }
+  }
+  
   /* Clear any X selections for this frame.  */
 #ifdef HAVE_X_WINDOWS
   if (FRAME_X_P (f))
@@ -2577,6 +2596,43 @@
 
   return unbind_to (count, Qnil);
 }
+
+DEFUN ("frame-with-environment", Fframe_with_environment, Sframe_with_environment, 0, 1, 0,
+       doc: /* Return the frame that has the environment variable list for FRAME.
+
+The frame-local environment variable list is normally shared between
+frames that were created in the same Emacsclient session.  The
+environment list is stored in a single frame's 'environment parameter;
+the other frames' 'environment parameter is set to this frame.  This
+function follows to chain of 'environment references to reach the
+frame that stores the actual local environment list, and returns that
+frame.  */)
+     (frame)
+     Lisp_Object frame;
+{
+  Lisp_Object hare, tortoise;
+
+  if (NILP (frame))
+    frame = selected_frame;
+  CHECK_FRAME (frame);
+
+  hare = tortoise = get_frame_param (XFRAME (frame), Qenvironment);
+  while (!NILP (hare) && FRAMEP (hare))
+    {
+      frame = hare;
+      hare = get_frame_param (XFRAME (hare), Qenvironment);
+      if (NILP (hare) || !FRAMEP (hare))
+        break;
+      frame = hare;
+      hare = get_frame_param (XFRAME (hare), Qenvironment);
+      tortoise = get_frame_param (XFRAME (tortoise), Qenvironment);
+      if (EQ (hare, tortoise))
+        error ("Cyclic frame-local environment indirection");
+    }
+
+  return frame;
+}
+
 
 DEFUN ("frame-char-height", Fframe_char_height, Sframe_char_height,
        0, 1, 0,
@@ -4232,6 +4288,8 @@
   staticpro (&Qtty_type);
   Qwindow_system = intern ("window-system");
   staticpro (&Qwindow_system);
+  Qenvironment = intern ("environment");
+  staticpro (&Qenvironment);
   
   Qface_set_after_frame_default = intern ("face-set-after-frame-default");
   staticpro (&Qface_set_after_frame_default);
@@ -4416,6 +4474,7 @@
   defsubr (&Sframe_parameters);
   defsubr (&Sframe_parameter);
   defsubr (&Smodify_frame_parameters);
+  defsubr (&Sframe_with_environment);
   defsubr (&Sframe_char_height);
   defsubr (&Sframe_char_width);
   defsubr (&Sframe_pixel_height);
--- a/src/frame.h	Thu Dec 29 02:10:23 2005 +0000
+++ b/src/frame.h	Thu Dec 29 04:31:04 2005 +0000
@@ -781,6 +781,7 @@
 extern Lisp_Object Qframep, Qframe_live_p;
 extern Lisp_Object Qtty, Qtty_type;
 extern Lisp_Object Qdevice, Qdisplay_live_p;
+extern Lisp_Object Qenvironment;
 
 extern struct frame *last_nonminibuf_frame;
 
--- a/src/lisp.h	Thu Dec 29 02:10:23 2005 +0000
+++ b/src/lisp.h	Thu Dec 29 04:31:04 2005 +0000
@@ -2998,6 +2998,7 @@
 EXFUN (Fframe_parameter, 2);
 EXFUN (Fframe_parameters, 1);
 EXFUN (Fmodify_frame_parameters, 2);
+EXFUN (Fframe_with_environment, 1);
 EXFUN (Fset_frame_height, 3);
 EXFUN (Fset_frame_width, 3);
 EXFUN (Fset_frame_size, 3);