aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaroly Lorentey2004-02-19 23:55:51 +0000
committerKaroly Lorentey2004-02-19 23:55:51 +0000
commit77134727c9430ee77bff150206fce33f2045dfc0 (patch)
tree4d288cd6b33a8f3ca914edbdbf8eed5d06e759a9
parentbfdfad9294d072ad12b670d23912998f7e439394 (diff)
downloademacs-77134727c9430ee77bff150206fce33f2045dfc0.tar.gz
emacs-77134727c9430ee77bff150206fce33f2045dfc0.zip
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
-rw-r--r--lib-src/emacsclient.c65
-rw-r--r--lisp/server.el144
2 files changed, 138 insertions, 71 deletions
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 771eeac05e6..90224fe51ee 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -70,11 +70,14 @@ int nowait = 0;
70/* Nonzero means args are expressions to be evaluated. --eval. */ 70/* Nonzero means args are expressions to be evaluated. --eval. */
71int eval = 0; 71int eval = 0;
72 72
73/* Nonzero means open a new graphical frame. */
74int window_system = 0;
75
73/* The display on which Emacs should work. --display. */ 76/* The display on which Emacs should work. --display. */
74char *display = NULL; 77char *display = NULL;
75 78
76/* Nonzero means open a new Emacs frame on the current terminal. */ 79/* Nonzero means open a new Emacs frame on the current terminal. */
77int frame = 0; 80int tty = 0;
78 81
79/* If non-NULL, the name of an editor to fallback to if the server 82/* If non-NULL, the name of an editor to fallback to if the server
80 is not running. --alternate-editor. */ 83 is not running. --alternate-editor. */
@@ -92,6 +95,7 @@ struct option longopts[] =
92 { "help", no_argument, NULL, 'H' }, 95 { "help", no_argument, NULL, 'H' },
93 { "version", no_argument, NULL, 'V' }, 96 { "version", no_argument, NULL, 'V' },
94 { "tty", no_argument, NULL, 't' }, 97 { "tty", no_argument, NULL, 't' },
98 { "window-system", no_argument, NULL, 'w' },
95 { "alternate-editor", required_argument, NULL, 'a' }, 99 { "alternate-editor", required_argument, NULL, 'a' },
96 { "socket-name", required_argument, NULL, 's' }, 100 { "socket-name", required_argument, NULL, 's' },
97 { "display", required_argument, NULL, 'd' }, 101 { "display", required_argument, NULL, 'd' },
@@ -107,11 +111,12 @@ decode_options (argc, argv)
107 char **argv; 111 char **argv;
108{ 112{
109 alternate_editor = getenv ("ALTERNATE_EDITOR"); 113 alternate_editor = getenv ("ALTERNATE_EDITOR");
114 display = getenv ("DISPLAY");
110 115
111 while (1) 116 while (1)
112 { 117 {
113 int opt = getopt_long (argc, argv, 118 int opt = getopt_long (argc, argv,
114 "VHnea:s:d:t", longopts, 0); 119 "VHnea:s:d:tw", longopts, 0);
115 120
116 if (opt == EOF) 121 if (opt == EOF)
117 break; 122 break;
@@ -149,7 +154,13 @@ decode_options (argc, argv)
149 break; 154 break;
150 155
151 case 't': 156 case 't':
152 frame = 1; 157 tty = 1;
158 window_system = 0;
159 break;
160
161 case 'w':
162 window_system = 1;
163 tty = 0;
153 break; 164 break;
154 165
155 case 'H': 166 case 'H':
@@ -163,11 +174,10 @@ decode_options (argc, argv)
163 } 174 }
164 } 175 }
165 176
166 if (frame) { 177 if (tty) {
167 nowait = 0; 178 nowait = 0;
168 display = 0; 179 display = 0;
169 } 180 }
170
171} 181}
172 182
173void 183void
@@ -182,6 +192,7 @@ The following OPTIONS are accepted:\n\
182-V, --version Just print a version info and return\n\ 192-V, --version Just print a version info and return\n\
183-H, --help Print this usage information message\n\ 193-H, --help Print this usage information message\n\
184-t, --tty Open a new Emacs frame on the current terminal\n\ 194-t, --tty Open a new Emacs frame on the current terminal\n\
195-w, --window-system Open a new graphical Emacs frame\n\
185-n, --no-wait Don't wait for the server to return\n\ 196-n, --no-wait Don't wait for the server to return\n\
186-e, --eval Evaluate the FILE arguments as ELisp expressions\n\ 197-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
187-d, --display=DISPLAY Visit the file in the given display\n\ 198-d, --display=DISPLAY Visit the file in the given display\n\
@@ -272,16 +283,6 @@ fail (void)
272 283
273int emacs_pid; 284int emacs_pid;
274 285
275#ifdef nec_ews_svr4
276extern char *_sobuf ;
277#else
278#if defined (USG) || defined (DGUX)
279unsigned char _sobuf[BUFSIZ+8];
280#else
281char _sobuf[BUFSIZ];
282#endif
283#endif
284
285/* A signal handler that passes the signal to the Emacs process. 286/* A signal handler that passes the signal to the Emacs process.
286 Useful for SIGWINCH. */ 287 Useful for SIGWINCH. */
287 288
@@ -395,7 +396,7 @@ main (argc, argv)
395 /* Process options. */ 396 /* Process options. */
396 decode_options (argc, argv); 397 decode_options (argc, argv);
397 398
398 if ((argc - optind < 1) && !eval && !frame) 399 if ((argc - optind < 1) && !eval && !tty && !window_system)
399 { 400 {
400 fprintf (stderr, "%s: file name or argument required\n", progname); 401 fprintf (stderr, "%s: file name or argument required\n", progname);
401 fprintf (stderr, "Try `%s --help' for more information\n", progname); 402 fprintf (stderr, "Try `%s --help' for more information\n", progname);
@@ -574,7 +575,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
574 fprintf (out, " "); 575 fprintf (out, " ");
575 } 576 }
576 577
577 if (frame) 578 if (tty)
578 { 579 {
579 char *tty_name = ttyname (fileno (stdin)); 580 char *tty_name = ttyname (fileno (stdin));
580 if (! tty_name) 581 if (! tty_name)
@@ -588,6 +589,9 @@ To start the server in Emacs, type \"M-x server-start\".\n",
588 quote_file_name (getenv("TERM"), out); 589 quote_file_name (getenv("TERM"), out);
589 fprintf (out, " "); 590 fprintf (out, " ");
590 } 591 }
592
593 if (window_system)
594 fprintf (out, "-window-system ");
591 595
592 if ((argc - optind > 0)) 596 if ((argc - optind > 0))
593 { 597 {
@@ -617,7 +621,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
617 } 621 }
618 else 622 else
619 { 623 {
620 if (!frame) 624 if (!tty && !window_system)
621 { 625 {
622 while ((str = fgets (string, BUFSIZ, stdin))) 626 while ((str = fgets (string, BUFSIZ, stdin)))
623 { 627 {
@@ -636,7 +640,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
636 return 0; 640 return 0;
637 } 641 }
638 642
639 if (!eval && !frame) 643 if (!eval && !tty)
640 { 644 {
641 printf ("Waiting for Emacs..."); 645 printf ("Waiting for Emacs...");
642 needlf = 2; 646 needlf = 2;
@@ -646,18 +650,29 @@ To start the server in Emacs, type \"M-x server-start\".\n",
646 /* Now, wait for an answer and print any messages. */ 650 /* Now, wait for an answer and print any messages. */
647 while ((str = fgets (string, BUFSIZ, in))) 651 while ((str = fgets (string, BUFSIZ, in)))
648 { 652 {
649 if (frame) 653 if (strprefix ("-emacs-pid ", str))
650 { 654 {
651 if (strprefix ("emacs-pid ", str)) 655 emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
652 { 656 }
653 emacs_pid = strtol (string + strlen ("emacs-pid"), NULL, 10); 657 else if (strprefix ("-print ", str))
654 } 658 {
659 if (needlf == 2)
660 printf ("\n");
661 printf ("%s", str + strlen ("-print "));
662 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
663 }
664 else if (strprefix ("-error ", str))
665 {
666 if (needlf == 2)
667 printf ("\n");
668 printf ("*ERROR*: %s", str + strlen ("-print "));
669 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
655 } 670 }
656 else 671 else
657 { 672 {
658 if (needlf == 2) 673 if (needlf == 2)
659 printf ("\n"); 674 printf ("\n");
660 printf ("%s", str); 675 printf ("*ERROR*: Unknown message: %s", str);
661 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; 676 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
662 } 677 }
663 } 678 }
diff --git a/lisp/server.el b/lisp/server.el
index 6d59b0d69c7..82f4ec26606 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -111,8 +111,18 @@ When a buffer is marked as \"done\", it is removed from this list.")
111Each element is (CLIENTID TTY) where CLIENTID is a string 111Each element is (CLIENTID TTY) where CLIENTID is a string
112that can be given to the server process to identify a client. 112that can be given to the server process to identify a client.
113TTY is the name of the tty device. 113TTY is the name of the tty device.
114When all the buffers of the client are marked as \"done\", 114
115the frame is deleted.") 115When all frames on the device are deleted, the server quits the
116connection to the client, and vice versa.")
117
118(defvar server-frames nil
119 "List of current window-system frames used by the server.
120Each element is (CLIENTID FRAME) where CLIENTID is a string
121that can be given to the server process to identify a client.
122FRAME is the frame that was opened by the client.
123
124When the frame is deleted, the server closes the connection to
125the client, and vice versa.")
116 126
117(defvar server-buffer-clients nil 127(defvar server-buffer-clients nil
118 "List of client ids for clients requesting editing of current buffer.") 128 "List of client ids for clients requesting editing of current buffer.")
@@ -211,7 +221,7 @@ are done with it in the server.")
211 (server-log (format "Status changed to %s" (process-status proc)) proc)) 221 (server-log (format "Status changed to %s" (process-status proc)) proc))
212 222
213(defun server-handle-delete-tty (tty) 223(defun server-handle-delete-tty (tty)
214 "Delete the client connection when the emacsclient frame is deleted." 224 "Delete the client connection when the emacsclient terminal device is closed."
215 (dolist (entry server-ttys) 225 (dolist (entry server-ttys)
216 (let ((proc (nth 0 entry)) 226 (let ((proc (nth 0 entry))
217 (term (nth 1 entry))) 227 (term (nth 1 entry)))
@@ -224,6 +234,20 @@ are done with it in the server.")
224 ;; `emacsclient -t -e '(delete-frame)'' correctly. 234 ;; `emacsclient -t -e '(delete-frame)'' correctly.
225 (setq server-clients (delq client server-clients)))))))) 235 (setq server-clients (delq client server-clients))))))))
226 236
237(defun server-handle-delete-frame (frame)
238 "Delete the client connection when the emacsclient frame is deleted."
239 (dolist (entry server-frames)
240 (let ((proc (nth 0 entry))
241 (f (nth 1 entry)))
242 (when (equal frame f)
243 (let ((client (assq proc server-clients)))
244 (setq server-frames (delq entry server-frames))
245 (delete-process (car client))
246 (when (assq proc server-clients)
247 ;; This seems to be necessary to handle
248 ;; `emacsclient -t -e '(delete-frame)'' correctly.
249 (setq server-clients (delq client server-clients))))))))
250
227(defun server-select-display (display) 251(defun server-select-display (display)
228 ;; If the current frame is on `display' we're all set. 252 ;; If the current frame is on `display' we're all set.
229 (unless (equal (frame-parameter (selected-frame) 'display) display) 253 (unless (equal (frame-parameter (selected-frame) 'display) display)
@@ -235,14 +259,14 @@ are done with it in the server.")
235 ;; and select it. 259 ;; and select it.
236 (unless (equal (frame-parameter (selected-frame) 'display) display) 260 (unless (equal (frame-parameter (selected-frame) 'display) display)
237 (select-frame 261 (select-frame
238 (make-frame-on-display 262 (make-frame-on-display display)))))
239 display
240 ;; This frame is only there in place of an actual "current display" 263 ;; This frame is only there in place of an actual "current display"
241 ;; setting, so we want it to be as unobtrusive as possible. That's 264 ;; setting, so we want it to be as unobtrusive as possible. That's
242 ;; what the invisibility is for. The minibuffer setting is so that 265 ;; what the invisibility is for. The minibuffer setting is so that
243 ;; we don't end up displaying a buffer in it (which noone would 266 ;; we don't end up displaying a buffer in it (which noone would
244 ;; notice). 267 ;; notice).
245 '((visibility . nil) (minibuffer . only))))))) 268 ;; XXX I have found this behaviour to be surprising and annoying. -- Lorentey
269 ;; '((visibility . nil) (minibuffer . only)))))))
246 270
247(defun server-unquote-arg (arg) 271(defun server-unquote-arg (arg)
248 (replace-regexp-in-string 272 (replace-regexp-in-string
@@ -301,6 +325,7 @@ Prefix arg means just kill any existing server communications subprocess."
301 (server-log (message "Restarting server"))) 325 (server-log (message "Restarting server")))
302 (letf (((default-file-modes) ?\700)) 326 (letf (((default-file-modes) ?\700))
303 (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty) 327 (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty)
328 (add-to-list 'delete-frame-functions 'server-handle-delete-frame)
304 (setq server-process 329 (setq server-process
305 (make-network-process 330 (make-network-process
306 :name "server" :family 'local :server t :noquery t 331 :name "server" :family 'local :server t :noquery t
@@ -324,6 +349,17 @@ Server mode runs a process that accepts commands from the
324 ;; nothing if there is one (for multiple Emacs sessions)? 349 ;; nothing if there is one (for multiple Emacs sessions)?
325 (server-start (not server-mode))) 350 (server-start (not server-mode)))
326 351
352(defmacro server-with-errors-reported (&rest forms)
353 "Evaluate FORMS; if an error occurs, report it to the client
354and return nil. Otherwise, return the result of the last form.
355For use in server-process-filter only."
356 `(condition-case err
357 (progn ,@forms)
358 (error (ignore-errors
359 (process-send-string
360 proc (concat "-error " (error-message-string err)))
361 (setq request "")))))
362
327(defun server-process-filter (proc string) 363(defun server-process-filter (proc string)
328 "Process a request from the server to edit some files. 364 "Process a request from the server to edit some files.
329PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." 365PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
@@ -339,7 +375,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
339 (coding-system (and default-enable-multibyte-characters 375 (coding-system (and default-enable-multibyte-characters
340 (or file-name-coding-system 376 (or file-name-coding-system
341 default-file-name-coding-system))) 377 default-file-name-coding-system)))
342 client nowait eval newframe 378 client nowait eval newframe display
343 registered ; t if the client is already added to server-clients. 379 registered ; t if the client is already added to server-clients.
344 (files nil) 380 (files nil)
345 (lineno 1) 381 (lineno 1)
@@ -353,37 +389,53 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
353 (cond 389 (cond
354 ((equal "-nowait" arg) (setq nowait t)) 390 ((equal "-nowait" arg) (setq nowait t))
355 ((equal "-eval" arg) (setq eval t)) 391 ((equal "-eval" arg) (setq eval t))
392
356 ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request)) 393 ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
357 (let ((display (server-unquote-arg (match-string 1 request)))) 394 (setq display (match-string 1 request)
358 (setq request (substring request (match-end 0))) 395 request (substring request (match-end 0))))
359 (condition-case err 396
360 (server-select-display display) 397 ;; Open a new X frame.
361 (error (process-send-string proc (nth 1 err)) 398 ((equal "-window-system" arg)
362 (setq request ""))))) 399 (server-with-errors-reported
363 ;; Open a new frame at the client. ARG is the name of the pseudo tty. 400 (let ((frame (make-frame-on-display
401 (or display
402 (frame-parameter nil 'display)
403 (getenv "DISPLAY")
404 (error "Please specify display")))))
405 (push (list proc frame) server-frames)
406 (select-frame frame)
407 ;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
408 (push client server-clients)
409 (setq registered t
410 newframe t))))
411
412 ;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
364 ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request)) 413 ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
365 (let ((tty (server-unquote-arg (match-string 1 request))) 414 (let ((tty (server-unquote-arg (match-string 1 request)))
366 (type (server-unquote-arg (match-string 2 request)))) 415 (type (server-unquote-arg (match-string 2 request))))
367 (setq request (substring request (match-end 0))) 416 (setq request (substring request (match-end 0)))
368 (condition-case err 417 (server-with-errors-reported
369 (let ((frame (make-frame-on-tty tty type))) 418 (let ((frame (make-frame-on-tty tty type)))
370 (setq server-ttys (cons (list (car client) (frame-tty-name frame)) server-ttys)) 419 (push (list (car client) (frame-tty-name frame)) server-ttys)
371 (process-send-string proc (concat "emacs-pid " (number-to-string (emacs-pid)) "\n")) 420 (process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n"))
372 (select-frame frame) 421 (select-frame frame)
373 ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right. 422 ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right.
374 (push client server-clients) 423 (push client server-clients)
375 (setq registered t 424 (setq registered t
376 newframe t)) 425 newframe t)))))
377 (error (process-send-string proc (concat (nth 1 err) "\n")) 426
378 (setq request "")))))
379 ;; ARG is a line number option. 427 ;; ARG is a line number option.
380 ((string-match "\\`\\+[0-9]+\\'" arg) 428 ((string-match "\\`\\+[0-9]+\\'" arg)
381 (setq lineno (string-to-int (substring arg 1)))) 429 (setq lineno (string-to-int (substring arg 1))))
430
382 ;; ARG is line number:column option. 431 ;; ARG is line number:column option.
383 ((string-match "\\`+\\([0-9]+\\):\\([0-9]+\\)\\'" arg) 432 ((string-match "\\`\\+\\([0-9]+\\):\\([0-9]+\\)\\'" arg)
384 (setq lineno (string-to-int (match-string 1 arg)) 433 (setq lineno (string-to-int (match-string 1 arg))
385 columnno (string-to-int (match-string 2 arg)))) 434 columnno (string-to-int (match-string 2 arg))))
435
436 ;; ARG is a filename or a Lisp expression.
386 (t 437 (t
438
387 ;; Undo the quoting that emacsclient does 439 ;; Undo the quoting that emacsclient does
388 ;; for certain special characters. 440 ;; for certain special characters.
389 (setq arg (server-unquote-arg arg)) 441 (setq arg (server-unquote-arg arg))
@@ -391,17 +443,14 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
391 (if coding-system 443 (if coding-system
392 (setq arg (decode-coding-string arg coding-system))) 444 (setq arg (decode-coding-string arg coding-system)))
393 (if eval 445 (if eval
394 (condition-case err 446 (server-with-errors-reported
395 (let ((v (eval (car (read-from-string arg))))) 447 (let ((v (eval (car (read-from-string arg)))))
396 (when (and (not newframe) v) 448 (when (and (not newframe) v)
397 (with-temp-buffer 449 (with-temp-buffer
398 (let ((standard-output (current-buffer))) 450 (let ((standard-output (current-buffer)))
399 (pp v) 451 (pp v)
400 (process-send-region proc (point-min) (point-max)))))) 452 (process-send-string proc "-print ")
401 (error 453 (process-send-region proc (point-min) (point-max)))))))
402 (ignore-errors
403 (process-send-string
404 proc (concat "*Error* " (error-message-string err))))))
405 454
406 ;; ARG is a file name. 455 ;; ARG is a file name.
407 ;; Collapse multiple slashes to single slashes. 456 ;; Collapse multiple slashes to single slashes.
@@ -409,6 +458,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
409 (push (list arg lineno columnno) files)) 458 (push (list arg lineno columnno) files))
410 (setq lineno 1) 459 (setq lineno 1)
411 (setq columnno 0))))) 460 (setq columnno 0)))))
461
412 (when files 462 (when files
413 (run-hooks 'pre-command-hook) 463 (run-hooks 'pre-command-hook)
414 (server-visit-files files client nowait) 464 (server-visit-files files client nowait)
@@ -506,15 +556,17 @@ FOR-KILLING if non-nil indicates that we are called from `kill-buffer'."
506 ;; If client now has no pending buffers, 556 ;; If client now has no pending buffers,
507 ;; tell it that it is done, and forget it entirely. 557 ;; tell it that it is done, and forget it entirely.
508 (unless (cdr client) 558 (unless (cdr client)
509 (let ((tty (assq (car client) server-ttys))) 559 (let ((tty (cadr (assq (car client) server-ttys)))
510 (if tty 560 (frame (cadr (assq (car client) server-frames))))
511 ;; Be careful, if we delete the process before the 561 (cond
512 ;; tty, then the terminal modes will not be restored 562 ;; Be careful, if we delete the process before the
513 ;; correctly. 563 ;; tty, then the terminal modes will not be restored
514 (delete-tty (cadr tty)) 564 ;; correctly.
515 (delete-process (car client)) 565 (tty (delete-tty tty))
516 (server-log "Close" (car client)) 566 (frame (delete-frame frame))
517 (setq server-clients (delq client server-clients)))))) 567 (t (delete-process (car client))
568 (server-log "Close" (car client))
569 (setq server-clients (delq client server-clients)))))))
518 (setq old-clients (cdr old-clients))) 570 (setq old-clients (cdr old-clients)))
519 (if (and (bufferp buffer) (buffer-name buffer)) 571 (if (and (bufferp buffer) (buffer-name buffer))
520 ;; We may or may not kill this buffer; 572 ;; We may or may not kill this buffer;