Mercurial > emacs
diff lisp/server.el @ 83043:78a785f205ea
Added -w option to emacsclient for opening a new X frame.
lib-src/emacsclient.c (window_system): New variable.
(frame): Renamed to tty for consistency with the option name.
(longopts, print_help_and_exit): Added -w option. (Suggested by Ami
Fischman <ami at fischman dot org>.
(decode_options): Initialize display to $DISPLAY. Handle -w option.
(main): Implement the -w option. Changed to a more elaborate protocol
between Emacs and emacsclient, in preparation to suspend support.
lisp/server.el (server-frames): New variable.
(server-handle-delete-frame): New function.
(server-start): Add it to delete-frame-functions.
(server-select-display): Don't make the new frame invisible.
(server-with-errors-reported): New macro for brevity.
(server-process-filter): Implement the "-window-system" command.
Use server-with-errors-reported. Fixed regexp for +line:column syntax.
Use the new protocol.
git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-83
| author | Karoly Lorentey <lorentey@elte.hu> |
|---|---|
| date | Thu, 19 Feb 2004 23:55:51 +0000 |
| parents | 1d2f73785d9d |
| children | 52039abab942 |
line wrap: on
line diff
--- a/lisp/server.el Thu Feb 19 13:25:32 2004 +0000 +++ b/lisp/server.el Thu Feb 19 23:55:51 2004 +0000 @@ -111,8 +111,18 @@ Each element is (CLIENTID TTY) where CLIENTID is a string that can be given to the server process to identify a client. TTY is the name of the tty device. -When all the buffers of the client are marked as \"done\", -the frame is deleted.") + +When all frames on the device are deleted, the server quits the +connection to the client, and vice versa.") + +(defvar server-frames nil + "List of current window-system frames used by the server. +Each element is (CLIENTID FRAME) where CLIENTID is a string +that can be given to the server process to identify a client. +FRAME is the frame that was opened by the client. + +When the frame is deleted, the server closes the connection to +the client, and vice versa.") (defvar server-buffer-clients nil "List of client ids for clients requesting editing of current buffer.") @@ -211,7 +221,7 @@ (server-log (format "Status changed to %s" (process-status proc)) proc)) (defun server-handle-delete-tty (tty) - "Delete the client connection when the emacsclient frame is deleted." + "Delete the client connection when the emacsclient terminal device is closed." (dolist (entry server-ttys) (let ((proc (nth 0 entry)) (term (nth 1 entry))) @@ -224,6 +234,20 @@ ;; `emacsclient -t -e '(delete-frame)'' correctly. (setq server-clients (delq client server-clients)))))))) +(defun server-handle-delete-frame (frame) + "Delete the client connection when the emacsclient frame is deleted." + (dolist (entry server-frames) + (let ((proc (nth 0 entry)) + (f (nth 1 entry))) + (when (equal frame f) + (let ((client (assq proc server-clients))) + (setq server-frames (delq entry server-frames)) + (delete-process (car client)) + (when (assq proc server-clients) + ;; This seems to be necessary to handle + ;; `emacsclient -t -e '(delete-frame)'' correctly. + (setq server-clients (delq client server-clients)))))))) + (defun server-select-display (display) ;; If the current frame is on `display' we're all set. (unless (equal (frame-parameter (selected-frame) 'display) display) @@ -235,14 +259,14 @@ ;; and select it. (unless (equal (frame-parameter (selected-frame) 'display) display) (select-frame - (make-frame-on-display - display + (make-frame-on-display display))))) ;; This frame is only there in place of an actual "current display" ;; setting, so we want it to be as unobtrusive as possible. That's ;; what the invisibility is for. The minibuffer setting is so that ;; we don't end up displaying a buffer in it (which noone would ;; notice). - '((visibility . nil) (minibuffer . only))))))) + ;; XXX I have found this behaviour to be surprising and annoying. -- Lorentey + ;; '((visibility . nil) (minibuffer . only))))))) (defun server-unquote-arg (arg) (replace-regexp-in-string @@ -301,6 +325,7 @@ (server-log (message "Restarting server"))) (letf (((default-file-modes) ?\700)) (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty) + (add-to-list 'delete-frame-functions 'server-handle-delete-frame) (setq server-process (make-network-process :name "server" :family 'local :server t :noquery t @@ -324,6 +349,17 @@ ;; nothing if there is one (for multiple Emacs sessions)? (server-start (not server-mode))) +(defmacro server-with-errors-reported (&rest forms) + "Evaluate FORMS; if an error occurs, report it to the client +and return nil. Otherwise, return the result of the last form. +For use in server-process-filter only." + `(condition-case err + (progn ,@forms) + (error (ignore-errors + (process-send-string + proc (concat "-error " (error-message-string err))) + (setq request ""))))) + (defun server-process-filter (proc string) "Process a request from the server to edit some files. PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." @@ -339,7 +375,7 @@ (coding-system (and default-enable-multibyte-characters (or file-name-coding-system default-file-name-coding-system))) - client nowait eval newframe + client nowait eval newframe display registered ; t if the client is already added to server-clients. (files nil) (lineno 1) @@ -353,37 +389,53 @@ (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 - (server-select-display display) - (error (process-send-string proc (nth 1 err)) - (setq request ""))))) - ;; Open a new frame at the client. ARG is the name of the pseudo tty. + (setq display (match-string 1 request) + request (substring request (match-end 0)))) + + ;; Open a new X frame. + ((equal "-window-system" arg) + (server-with-errors-reported + (let ((frame (make-frame-on-display + (or display + (frame-parameter nil 'display) + (getenv "DISPLAY") + (error "Please specify display"))))) + (push (list proc frame) server-frames) + (select-frame frame) + ;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right. + (push client server-clients) + (setq registered t + newframe t)))) + + ;; Open a new tty frame at the client. ARG is the name of the pseudo tty. ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request)) (let ((tty (server-unquote-arg (match-string 1 request))) (type (server-unquote-arg (match-string 2 request)))) (setq request (substring request (match-end 0))) - (condition-case err - (let ((frame (make-frame-on-tty tty type))) - (setq server-ttys (cons (list (car client) (frame-tty-name frame)) server-ttys)) - (process-send-string proc (concat "emacs-pid " (number-to-string (emacs-pid)) "\n")) - (select-frame frame) - ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right. - (push client server-clients) - (setq registered t - newframe t)) - (error (process-send-string proc (concat (nth 1 err) "\n")) - (setq request ""))))) + (server-with-errors-reported + (let ((frame (make-frame-on-tty tty type))) + (push (list (car client) (frame-tty-name frame)) server-ttys) + (process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n")) + (select-frame frame) + ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right. + (push client server-clients) + (setq registered t + newframe t))))) + ;; ARG is a line number option. ((string-match "\\`\\+[0-9]+\\'" arg) (setq lineno (string-to-int (substring arg 1)))) + ;; ARG is line number:column option. - ((string-match "\\`+\\([0-9]+\\):\\([0-9]+\\)\\'" arg) + ((string-match "\\`\\+\\([0-9]+\\):\\([0-9]+\\)\\'" arg) (setq lineno (string-to-int (match-string 1 arg)) columnno (string-to-int (match-string 2 arg)))) + + ;; ARG is a filename or a Lisp expression. (t + ;; Undo the quoting that emacsclient does ;; for certain special characters. (setq arg (server-unquote-arg arg)) @@ -391,17 +443,14 @@ (if coding-system (setq arg (decode-coding-string arg coding-system))) (if eval - (condition-case err - (let ((v (eval (car (read-from-string arg))))) - (when (and (not newframe) v) - (with-temp-buffer - (let ((standard-output (current-buffer))) - (pp v) - (process-send-region proc (point-min) (point-max)))))) - (error - (ignore-errors - (process-send-string - proc (concat "*Error* " (error-message-string err)))))) + (server-with-errors-reported + (let ((v (eval (car (read-from-string arg))))) + (when (and (not newframe) v) + (with-temp-buffer + (let ((standard-output (current-buffer))) + (pp v) + (process-send-string proc "-print ") + (process-send-region proc (point-min) (point-max))))))) ;; ARG is a file name. ;; Collapse multiple slashes to single slashes. @@ -409,6 +458,7 @@ (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) @@ -506,15 +556,17 @@ ;; If client now has no pending buffers, ;; tell it that it is done, and forget it entirely. (unless (cdr client) - (let ((tty (assq (car client) server-ttys))) - (if tty - ;; Be careful, if we delete the process before the - ;; tty, then the terminal modes will not be restored - ;; correctly. - (delete-tty (cadr tty)) - (delete-process (car client)) - (server-log "Close" (car client)) - (setq server-clients (delq client server-clients)))))) + (let ((tty (cadr (assq (car client) server-ttys))) + (frame (cadr (assq (car client) server-frames)))) + (cond + ;; Be careful, if we delete the process before the + ;; tty, then the terminal modes will not be restored + ;; correctly. + (tty (delete-tty tty)) + (frame (delete-frame frame)) + (t (delete-process (car client)) + (server-log "Close" (car client)) + (setq server-clients (delq client server-clients))))))) (setq old-clients (cdr old-clients))) (if (and (bufferp buffer) (buffer-name buffer)) ;; We may or may not kill this buffer;
