]> code.delx.au - gnu-emacs/blobdiff - lisp/server.el
(server-visit-files): If `minibuffer-auto-raise' has been set to t, respect it.
[gnu-emacs] / lisp / server.el
index 50bf6f766ec58778cba729d491fba55ae8730524..bcb79d6b9acbcb68849d9e68a09e8e903b7c4b59 100644 (file)
@@ -112,9 +112,11 @@ If set, the server accepts remote connections; otherwise it is local."
   :version "22.1")
 (put 'server-auth-dir 'risky-local-variable t)
 
-(defvar server-auth-key nil
-  "The current server authentication key.")
-(put 'server-auth-key 'risky-local-variable t)
+(defcustom server-raise-frame t
+  "*If non-nil, raise frame when switching to a buffer."
+  :group 'server
+  :type 'boolean
+  :version "22.1")
 
 (defcustom server-visit-hook nil
   "*Hook run when visiting a file for the Emacs server."
@@ -228,6 +230,12 @@ are done with it in the server.")
   (when (and (eq (process-status proc) 'open)
             (process-query-on-exit-flag proc))
     (set-process-query-on-exit-flag proc nil))
+  ;; Delete the associated connection file, if applicable.
+  ;; This is actually problematic: the file may have been overwritten by
+  ;; another Emacs server in the mean time, so it's not ours any more.
+  ;; (and (process-contact proc :server)
+  ;;      (eq (process-status proc) 'closed)
+  ;;      (ignore-errors (delete-file (process-get proc :server-file))))
   (server-log (format "Status changed to %s" (process-status proc)) proc))
 
 (defun server-select-display (display)
@@ -307,61 +315,59 @@ Prefix arg means just kill any existing server communications subprocess."
   (interactive "P")
   (when server-process
     ;; kill it dead!
-    (ignore-errors (delete-process server-process))
-    (ignore-errors
-      ;; Delete the socket or authentication files made by previous
-      ;; server invocations.
-      (if (eq (process-contact server-process :family) 'local)
-      (delete-file (expand-file-name server-name server-socket-dir))
-        (setq server-auth-key nil)
-        (delete-file (expand-file-name server-name server-auth-dir)))))
+    (ignore-errors (delete-process server-process)))
   ;; If this Emacs already had a server, clear out associated status.
   (while server-clients
     (let ((buffer (nth 1 (car server-clients))))
       (server-buffer-done buffer)))
   ;; Now any previous server is properly stopped.
   (unless leave-dead
-    ;; Make sure there is a safe directory in which to place the socket.
-    (server-ensure-safe-dir
-     (if server-use-tcp server-auth-dir server-socket-dir))
-    (when server-process
-       (server-log (message "Restarting server")))
-    (letf (((default-file-modes) ?\700))
-      (setq server-process
-            (apply #'make-network-process
-                   :name server-name
-                   :server t
-                   :noquery t
-                   :sentinel 'server-sentinel
-                   :filter 'server-process-filter
-                   ;; We must receive file names without being decoded.
-                   ;; Those are decoded by server-process-filter according
-                   ;; to file-name-coding-system.
-                   :coding 'raw-text
-                   ;; The rest of the args depends on the kind of socket used.
-                   (if server-use-tcp
-                       (list :family nil
-                             :service t
-                             :host (or server-host 'local)
-                             :plist '(:authenticated nil))
-                     (list :family 'local
-                           :service (expand-file-name server-name server-socket-dir)
-                           :plist '(:authenticated t)))))
-      (unless server-process (error "Could not start server process"))
-      (when server-use-tcp
-        (setq server-auth-key
-              (loop
-                 ;; The auth key is a 64-byte string of random chars in the
-                 ;; range `!'..`~'.
-                for i below 64
-                 collect (+ 33 (random 94)) into auth
-                 finally return (concat auth)))
-        (with-temp-file (expand-file-name server-name server-auth-dir)
-          (set-buffer-multibyte nil)
-          (setq buffer-file-coding-system 'no-conversion)
-          (insert (format-network-address
-                   (process-contact server-process :local))
-                  "\n" server-auth-key))))))
+    (let* ((server-dir (if server-use-tcp server-auth-dir server-socket-dir))
+           (server-file (expand-file-name server-name server-dir)))
+      ;; Make sure there is a safe directory in which to place the socket.
+      (server-ensure-safe-dir server-dir)
+      ;; Remove any leftover socket or authentication file.
+      (ignore-errors (delete-file server-file))
+      (when server-process
+        (server-log (message "Restarting server")))
+      (letf (((default-file-modes) ?\700))
+        (setq server-process
+              (apply #'make-network-process
+                     :name server-name
+                     :server t
+                     :noquery t
+                     :sentinel 'server-sentinel
+                     :filter 'server-process-filter
+                     ;; We must receive file names without being decoded.
+                     ;; Those are decoded by server-process-filter according
+                     ;; to file-name-coding-system.
+                     :coding 'raw-text
+                     ;; The rest of the args depends on the kind of socket used.
+                     (if server-use-tcp
+                         (list :family nil
+                               :service t
+                               :host (or server-host 'local)
+                               :plist '(:authenticated nil))
+                       (list :family 'local
+                             :service server-file
+                             :plist '(:authenticated t)))))
+        (unless server-process (error "Could not start server process"))
+        (when server-use-tcp
+          (let ((auth-key
+                 (loop
+                    ;; The auth key is a 64-byte string of random chars in the
+                    ;; range `!'..`~'.
+                    for i below 64
+                    collect (+ 33 (random 94)) into auth
+                    finally return (concat auth))))
+            (process-put server-process :auth-key auth-key)
+            (with-temp-file server-file
+              (set-buffer-multibyte nil)
+              (setq buffer-file-coding-system 'no-conversion)
+              (insert (format-network-address
+                       (process-contact server-process :local))
+                      " " (int-to-string (emacs-pid))
+                      "\n" auth-key))))))))
 
 ;;;###autoload
 (define-minor-mode server-mode
@@ -382,12 +388,13 @@ PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
   ;; First things first: let's check the authentication
   (unless (process-get proc :authenticated)
     (if (and (string-match "-auth \\(.*?\\)\n" string)
-             (string= (match-string 1 string) server-auth-key))
+             (equal (match-string 1 string) (process-get proc :auth-key)))
         (progn
           (setq string (substring string (match-end 0)))
           (process-put proc :authenticated t)
           (server-log "Authentication successful" proc))
       (server-log "Authentication failed" proc)
+      (process-send-string proc "Authentication failed")
       (delete-process proc)
       ;; We return immediately
       (return-from server-process-filter)))
@@ -415,52 +422,48 @@ PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
        (let ((arg (substring request (match-beginning 0) (1- (match-end 0)))))
          (setq request (substring request (match-end 0)))
          (cond
-          ((equal "-nowait" arg) (setq nowait t))
-          ((equal "-eval" arg) (setq eval t))
-          ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
-           (let ((display (server-unquote-arg (match-string 1 request))))
-             (setq request (substring request (match-end 0)))
-             (condition-case err
-                 (setq tmp-frame (server-select-display display))
-               (error (process-send-string proc (nth 1 err))
-                      (setq request "")))))
-          ;; ARG is a line number option.
-          ((string-match "\\`\\+[0-9]+\\'" arg)
-           (setq lineno (string-to-number (substring arg 1))))
-          ;; ARG is line number:column option.
-          ((string-match "\\`+\\([0-9]+\\):\\([0-9]+\\)\\'" arg)
-           (setq lineno (string-to-number (match-string 1 arg))
-                 columnno (string-to-number (match-string 2 arg))))
-          (t
-           ;; Undo the quoting that emacsclient does
-           ;; for certain special characters.
-           (setq arg (server-unquote-arg arg))
-           ;; Now decode the file name if necessary.
-           (when coding-system
-             (setq arg (decode-coding-string arg coding-system)))
-           (if eval
-               (let* (errorp
-                      (v (condition-case errobj
-                            (eval (car (read-from-string arg)))
-                          (error (setq errorp t) errobj))))
-                 (when v
-                   (with-temp-buffer
-                     (let ((standard-output (current-buffer)))
-                       (if errorp (princ "error: "))
-                       (pp v)
-                       ;; Suppress the error signalled when the pipe to
-                       ;; PROC is closed.
-                       (condition-case err
-                           (process-send-region proc (point-min) (point-max))
-                         (file-error nil)
-                         (error nil))
-                       ))))
-             ;; ARG is a file name.
-             ;; Collapse multiple slashes to single slashes.
-             (setq arg (command-line-normalize-file-name arg))
-             (push (list arg lineno columnno) files))
-           (setq lineno 1)
-           (setq columnno 0)))))
+            ((equal "-nowait" arg) (setq nowait t))
+            ((equal "-eval" arg) (setq eval t))
+            ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
+             (let ((display (server-unquote-arg (match-string 1 request))))
+               (setq request (substring request (match-end 0)))
+               (condition-case err
+                   (setq tmp-frame (server-select-display display))
+                 (error (process-send-string proc (nth 1 err))
+                        (setq request "")))))
+            ;; ARG is a line number option.
+            ((string-match "\\`\\+[0-9]+\\'" arg)
+             (setq lineno (string-to-number (substring arg 1))))
+            ;; ARG is line number:column option.
+            ((string-match "\\`+\\([0-9]+\\):\\([0-9]+\\)\\'" arg)
+             (setq lineno (string-to-number (match-string 1 arg))
+                   columnno (string-to-number (match-string 2 arg))))
+            (t
+             ;; Undo the quoting that emacsclient does
+             ;; for certain special characters.
+             (setq arg (server-unquote-arg arg))
+             ;; Now decode the file name if necessary.
+             (when coding-system
+               (setq arg (decode-coding-string arg coding-system)))
+             (if eval
+                 (let* (errorp
+                        (v (condition-case errobj
+                               (eval (car (read-from-string arg)))
+                             (error (setq errorp t) errobj))))
+                   (when v
+                     (with-temp-buffer
+                       (let ((standard-output (current-buffer)))
+                         (when errorp (princ "error: "))
+                         (pp v)
+                         (ignore-errors
+                           (process-send-region proc (point-min) (point-max)))
+                         ))))
+               ;; ARG is a file name.
+               ;; Collapse multiple slashes to single slashes.
+               (setq arg (command-line-normalize-file-name arg))
+               (push (list arg lineno columnno) files))
+             (setq lineno 1)
+             (setq columnno 0)))))
       (when files
        (run-hooks 'pre-command-hook)
        (server-visit-files files client nowait)
@@ -478,7 +481,7 @@ PROC is the server process.  Format of STRING is \"PATH PATH PATH... \\n\"."
          (run-hooks 'server-switch-hook)
          (unless nowait
            (message "%s" (substitute-command-keys
-                     "When done with a buffer, type \\[server-edit]")))))
+                           "When done with a buffer, type \\[server-edit]")))))
       (when (frame-live-p tmp-frame)
         ;; Delete tmp-frame or make it visible depending on whether it's
         ;; been used or not.
@@ -508,20 +511,22 @@ so don't mark these buffers specially, just visit them normally."
        ;; If there is an existing buffer modified or the file is
        ;; modified, revert it.  If there is an existing buffer with
        ;; deleted file, offer to write it.
-       (let* ((filen (car file))
+       (let* ((minibuffer-auto-raise (or server-raise-frame
+                                          minibuffer-auto-raise))
+              (filen (car file))
               (obuf (get-file-buffer filen)))
          (add-to-history 'file-name-history filen)
          (if (and obuf (set-buffer obuf))
              (progn
                (cond ((file-exists-p filen)
-                      (if (not (verify-visited-file-modtime obuf))
-                          (revert-buffer t nil)))
+                      (when (not (verify-visited-file-modtime obuf))
+                         (revert-buffer t nil)))
                      (t
-                      (if (y-or-n-p
-                           (concat "File no longer exists: "
-                                   filen
-                                   ", write buffer to file? "))
-                          (write-file filen))))
+                      (when (y-or-n-p
+                              (concat "File no longer exists: "
+                                      filen
+                                      ", write buffer to file? "))
+                         (write-file filen))))
                (setq server-existing-buffer t)
                (server-goto-line-column file))
            (set-buffer (find-file-noselect filen))
@@ -675,12 +680,12 @@ If invoked with a prefix argument, or if there is no server process running,
 starts server process and that is all.  Invoked by \\[server-edit]."
   (interactive "P")
   (cond
-   ((or arg
-       (not server-process)
-       (memq (process-status server-process) '(signal exit)))
-    (server-mode 1))
-   (server-clients (apply 'server-switch-buffer (server-done)))
-   (t (message "No server editing buffers exist"))))
+    ((or arg
+         (not server-process)
+         (memq (process-status server-process) '(signal exit)))
+     (server-mode 1))
+    (server-clients (apply 'server-switch-buffer (server-done)))
+    (t (message "No server editing buffers exist"))))
 
 (defun server-switch-buffer (&optional next-buffer killed-one)
   "Switch to another buffer, preferably one that has a client.
@@ -705,11 +710,9 @@ Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it."
        (let ((win (get-buffer-window next-buffer 0)))
          (if (and win (not server-window))
              ;; The buffer is already displayed: just reuse the window.
-             (let ((frame (window-frame win)))
-               (when (eq (frame-visible-p frame) 'icon)
-                 (raise-frame frame))
-               (select-window win)
-               (set-buffer next-buffer))
+              (progn
+                (select-window win)
+                (set-buffer next-buffer))
            ;; Otherwise, let's find an appropriate window.
            (cond ((and (windowp server-window)
                        (window-live-p server-window))
@@ -733,7 +736,9 @@ Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it."
                (switch-to-buffer next-buffer)
              ;; After all the above, we might still have ended up with
              ;; a minibuffer/dedicated-window (if there's no other).
-             (error (pop-to-buffer next-buffer)))))))))
+             (error (pop-to-buffer next-buffer)))))))
+    (when server-raise-frame
+      (select-frame-set-input-focus (window-frame (selected-window))))))
 
 (define-key ctl-x-map "#" 'server-edit)