aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorKaroly Lorentey2004-02-28 01:23:39 +0000
committerKaroly Lorentey2004-02-28 01:23:39 +0000
commit0b0d3e0bcefdde298893aaad2e816e1503cef222 (patch)
tree439342044857514ad784de0470f5546eb9c3ef9a /lisp
parent2fc0cf2aefa777e5fe48596e2d43774b28051931 (diff)
downloademacs-0b0d3e0bcefdde298893aaad2e816e1503cef222.tar.gz
emacs-0b0d3e0bcefdde298893aaad2e816e1503cef222.zip
Implemented suspending of emacsclient frames.
lib-src/emacsclient.c (quote_file_name): Renamed to quote_argument. (unquote_argument, handle_sigcont, handle_sigtstp): New functions. (out, in): New global variables for communicating with the Emacs process. (init_signals): Set up handlers for SIGCONT, SIGTSTP and SIGTTOU. (main): Changed out and in to global variables. Prepend `-eval' or '-file' to each argument. Use fsync to force sending the strings to Emacs. Removed obsolete -bad-version code. Support the -suspend command. Cleaned up newline handling. lisp/frame.el (suspend-frame): New function. Substitute key definition of suspend-emacs with suspend-frame. lisp/server.el (server-log): Cosmetic change in log format. (server-handle-delete-tty, server-handle-delete-frame): Added logging. (server-handle-suspend-tty, server-quote-arg): New functions. (server-start): Install server-handle-suspend-tty. (server-process-filter): Reorganized source code for clarity. Implemented -resume, -suspend and -ignore commands. lisp/term/x-win.el (x-initialize-window-system): Don't change the binding of C-z. src/cm.c: Replaced TTY_INPUT, TTY_OUTPUT, TTY_TERMSCRIPT calls with their macro expansion. src/dispnew.c: Ditto. src/frame.c: Ditto. src/keyboard.c: Ditto. src/sysdep.c: Ditto. src/keyboard.c (tty_read_avail_input): Don't read if the terminal is suspended. src/sysdep.c (discard_tty_input, init_sys_modes, reset_sys_modes): Ditto. src/term.c (tty_set_terminal_modes, tty_reset_terminal_modes): Ditto. src/term.c (Vsuspend_tty_functions, Vresume_tty_functions): New hooks. (syms_of_term): Defvar them. (term_init): Don't allow opening a new frame on a suspended tty device. (Fsuspend_tty, Fresume_tty): New functions. (syms_of_term): Defsubr them. src/termchar.c (struct tty_display_info): Update documentation of input and output. (TTY_INPUT, TTY_OUTPUT, TTY_TERMSCRIPT): Removed. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-105
Diffstat (limited to 'lisp')
-rw-r--r--lisp/frame.el18
-rw-r--r--lisp/server.el296
-rw-r--r--lisp/term/x-win.el6
3 files changed, 201 insertions, 119 deletions
diff --git a/lisp/frame.el b/lisp/frame.el
index 8d76c7b70ba..54bccd93970 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -750,6 +750,22 @@ Otherwise, that variable should be nil."
750 (iconify-frame) 750 (iconify-frame)
751 (make-frame-visible))) 751 (make-frame-visible)))
752 752
753(defun suspend-frame ()
754 "Do whatever is right to suspend the current frame.
755Calls `suspend-emacs' if invoked from the controlling terminal,
756`suspend-tty' from a secondary terminal, and
757`iconify-or-deiconify-frame' from an X frame."
758 (interactive)
759 (let ((type (framep (selected-frame))))
760 (cond
761 ((eq type 'x) (iconify-or-deiconify-frame))
762 ((eq type t)
763 (if (frame-tty-name)
764 (suspend-tty)
765 (suspend-emacs)))
766 (t (suspend-emacs)))))
767
768
753(defun make-frame-names-alist () 769(defun make-frame-names-alist ()
754 (let* ((current-frame (selected-frame)) 770 (let* ((current-frame (selected-frame))
755 (falist 771 (falist
@@ -1374,6 +1390,8 @@ Use Custom to set this variable to get the display updated."
1374(define-key ctl-x-5-map "0" 'delete-frame) 1390(define-key ctl-x-5-map "0" 'delete-frame)
1375(define-key ctl-x-5-map "o" 'other-frame) 1391(define-key ctl-x-5-map "o" 'other-frame)
1376 1392
1393(substitute-key-definition 'suspend-emacs 'suspend-frame global-map)
1394
1377(provide 'frame) 1395(provide 'frame)
1378 1396
1379;;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56 1397;;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56
diff --git a/lisp/server.el b/lisp/server.el
index a1619471e56..aac3da13e4f 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -186,7 +186,7 @@ are done with it in the server.")
186 (with-current-buffer "*server*" 186 (with-current-buffer "*server*"
187 (goto-char (point-max)) 187 (goto-char (point-max))
188 (insert (current-time-string) 188 (insert (current-time-string)
189 (if client (format " %s:" client) " ") 189 (if client (format " %s: " client) " ")
190 string) 190 string)
191 (or (bolp) (newline))))) 191 (or (bolp) (newline)))))
192 192
@@ -227,6 +227,7 @@ are done with it in the server.")
227 (term (nth 1 entry))) 227 (term (nth 1 entry)))
228 (when (equal term tty) 228 (when (equal term tty)
229 (let ((client (assq proc server-clients))) 229 (let ((client (assq proc server-clients)))
230 (server-log (format "server-handle-delete-tty, tty %s" tty) (car client))
230 (setq server-ttys (delq entry server-ttys)) 231 (setq server-ttys (delq entry server-ttys))
231 (delete-process (car client)) 232 (delete-process (car client))
232 (when (assq proc server-clients) 233 (when (assq proc server-clients)
@@ -234,6 +235,16 @@ are done with it in the server.")
234 ;; `emacsclient -t -e '(delete-frame)'' correctly. 235 ;; `emacsclient -t -e '(delete-frame)'' correctly.
235 (setq server-clients (delq client server-clients)))))))) 236 (setq server-clients (delq client server-clients))))))))
236 237
238(defun server-handle-suspend-tty (tty)
239 "Notify the emacsclient process to suspend itself when its tty device is suspended."
240 (dolist (entry server-ttys)
241 (let ((proc (nth 0 entry))
242 (term (nth 1 entry)))
243 (when (equal term tty)
244 (let ((process (car (assq proc server-clients))))
245 (server-log (format "server-handle-suspend-tty, tty %s" tty) process)
246 (process-send-string process "-suspend \n"))))))
247
237(defun server-handle-delete-frame (frame) 248(defun server-handle-delete-frame (frame)
238 "Delete the client connection when the emacsclient frame is deleted." 249 "Delete the client connection when the emacsclient frame is deleted."
239 (dolist (entry server-frames) 250 (dolist (entry server-frames)
@@ -241,6 +252,7 @@ are done with it in the server.")
241 (f (nth 1 entry))) 252 (f (nth 1 entry)))
242 (when (equal frame f) 253 (when (equal frame f)
243 (let ((client (assq proc server-clients))) 254 (let ((client (assq proc server-clients)))
255 (server-log (format "server-handle-delete-frame, frame %s" frame) (car client))
244 (setq server-frames (delq entry server-frames)) 256 (setq server-frames (delq entry server-frames))
245 (delete-process (car client)) 257 (delete-process (car client))
246 (when (assq proc server-clients) 258 (when (assq proc server-clients)
@@ -278,6 +290,19 @@ are done with it in the server.")
278 (t " "))) 290 (t " ")))
279 arg t t)) 291 arg t t))
280 292
293(defun server-quote-arg (arg)
294 "In NAME, insert a & before each &, each space, each newline, and -.
295Change spaces to underscores, too, so that the return value never
296contains a space."
297 (replace-regexp-in-string
298 "[-&\n ]" (lambda (s)
299 (case (aref s 0)
300 (?& "&&")
301 (?- "&-")
302 (?\n "&n")
303 (?\s "&_")))
304 arg t t))
305
281(defun server-ensure-safe-dir (dir) 306(defun server-ensure-safe-dir (dir)
282 "Make sure DIR is a directory with no race-condition issues. 307 "Make sure DIR is a directory with no race-condition issues.
283Creates the directory if necessary and makes sure: 308Creates the directory if necessary and makes sure:
@@ -325,6 +350,7 @@ Prefix arg means just kill any existing server communications subprocess."
325 (server-log (message "Restarting server"))) 350 (server-log (message "Restarting server")))
326 (letf (((default-file-modes) ?\700)) 351 (letf (((default-file-modes) ?\700))
327 (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty) 352 (add-to-list 'delete-tty-after-functions 'server-handle-delete-tty)
353 (add-to-list 'suspend-tty-functions 'server-handle-suspend-tty)
328 (add-to-list 'delete-frame-functions 'server-handle-delete-frame) 354 (add-to-list 'delete-frame-functions 'server-handle-delete-frame)
329 (setq server-process 355 (setq server-process
330 (make-network-process 356 (make-network-process
@@ -358,140 +384,182 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
358 (setq string (concat prev string)) 384 (setq string (concat prev string))
359 (process-put proc 'previous-string nil))) 385 (process-put proc 'previous-string nil)))
360 (condition-case err 386 (condition-case err
361 ;; If the input is multiple lines, 387 (progn
362 ;; process each line individually. 388 ;; If the input is multiple lines,
363 (while (string-match "\n" string) 389 ;; process each line individually.
364 (let ((request (substring string 0 (match-beginning 0))) 390 (while (string-match "\n" string)
365 (coding-system (and default-enable-multibyte-characters 391 (let ((request (substring string 0 (match-beginning 0)))
366 (or file-name-coding-system 392 (coding-system (and default-enable-multibyte-characters
367 default-file-name-coding-system))) 393 (or file-name-coding-system
368 client nowait eval newframe display version-checked 394 default-file-name-coding-system)))
369 registered ; t if the client is already added to server-clients. 395 client nowait newframe display version-checked
370 (files nil) 396 dontkill ; t if the client should not be killed.
371 (lineno 1) 397 registered ; t if the client is already added to server-clients.
372 (columnno 0)) 398 (files nil)
373 ;; Remove this line from STRING. 399 (lineno 1)
374 (setq string (substring string (match-end 0))) 400 (columnno 0))
375 (setq client (cons proc nil)) 401 ;; Remove this line from STRING.
376 (while (string-match "[^ ]* " request) 402 (setq string (substring string (match-end 0)))
377 (let ((arg (substring request (match-beginning 0) (1- (match-end 0))))) 403 (setq client (cons proc nil))
378 (setq request (substring request (match-end 0))) 404 (while (string-match "[^ ]* " request)
379 (cond 405 (let ((arg (substring request (match-beginning 0) (1- (match-end 0)))))
380 ;; Check version numbers. 406 (setq request (substring request (match-end 0)))
381 ((and (equal "-version" arg) (string-match "\\([0-9.]+\\) " request)) 407 (cond
382 (let* ((client-version (match-string 1 request)) 408 ;; Check version numbers.
383 (truncated-emacs-version (substring emacs-version 0 (length client-version)))) 409 ((and (equal "-version" arg) (string-match "\\([0-9.]+\\) " request))
384 (setq request (substring request (match-end 0))) 410 (let* ((client-version (match-string 1 request))
385 (if (equal client-version truncated-emacs-version) 411 (truncated-emacs-version (substring emacs-version 0 (length client-version))))
386 (progn 412 (setq request (substring request (match-end 0)))
387 (process-send-string proc "-good-version \n") 413 (if (equal client-version truncated-emacs-version)
388 (setq version-checked t)) 414 (progn
389 (error (concat "Version mismatch: Emacs is " truncated-emacs-version ", emacsclient is " client-version))))) 415 (process-send-string proc "-good-version \n")
390 416 (setq version-checked t))
391 ((equal "-nowait" arg) (setq nowait t)) 417 (error (concat "Version mismatch: Emacs is " truncated-emacs-version ", emacsclient is " client-version)))))
392 ((equal "-eval" arg) (setq eval t)) 418
393 419 ((equal "-nowait" arg) (setq nowait t))
394 ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request)) 420
395 (setq display (match-string 1 request) 421 ((and (equal "-display" arg) (string-match "\\([^ ]*\\) " request))
396 request (substring request (match-end 0)))) 422 (setq display (match-string 1 request)
397 423 request (substring request (match-end 0))))
398 ;; Open a new X frame. 424
399 ((equal "-window-system" arg) 425 ;; Open a new X frame.
400 (unless version-checked 426 ((equal "-window-system" arg)
401 (error "Protocol error; make sure to use the correct version of emacsclient"))
402 (let ((frame (make-frame-on-display
403 (or display
404 (frame-parameter nil 'display)
405 (getenv "DISPLAY")
406 (error "Please specify display")))))
407 (push (list proc frame) server-frames)
408 (select-frame frame)
409 ;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
410 (push client server-clients)
411 (setq registered t
412 newframe t)))
413
414 ;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
415 ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
416 (let ((tty (server-unquote-arg (match-string 1 request)))
417 (type (server-unquote-arg (match-string 2 request))))
418 (setq request (substring request (match-end 0)))
419 (unless version-checked 427 (unless version-checked
420 (error "Protocol error; make sure to use the correct version of emacsclient")) 428 (error "Protocol error; make sure to use the correct version of emacsclient"))
421 (let ((frame (make-frame-on-tty tty type))) 429 (let ((frame (make-frame-on-display
422 (push (list (car client) (frame-tty-name frame)) server-ttys) 430 (or display
423 (process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n")) 431 (frame-parameter nil 'display)
432 (getenv "DISPLAY")
433 (error "Please specify display")))))
434 (push (list proc frame) server-frames)
424 (select-frame frame) 435 (select-frame frame)
425 ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right. 436 ;; This makes sure that `emacsclient -w -e '(delete-frame)'' works right.
426 (push client server-clients) 437 (push client server-clients)
427 (setq registered t 438 (setq registered t
428 newframe t)))) 439 newframe t
429 440 dontkill t)))
430 ;; ARG is a line number option. 441
431 ((string-match "\\`\\+[0-9]+\\'" arg) 442 ;; Resume a suspended tty frame.
432 (setq lineno (string-to-int (substring arg 1)))) 443 ((equal "-resume" arg)
433 444 (let ((tty (cadr (assq (car client) server-ttys))))
434 ;; ARG is line number:column option. 445 (setq dontkill t)
435 ((string-match "\\`\\+\\([0-9]+\\):\\([0-9]+\\)\\'" arg) 446 (when tty (resume-tty tty))))
436 (setq lineno (string-to-int (match-string 1 arg)) 447
437 columnno (string-to-int (match-string 2 arg)))) 448 ;; Suspend the client's frame. (In case we get out of
438 449 ;; sync, and a C-z sends a SIGTSTP to emacsclient.)
439 ;; ARG is a filename or a Lisp expression. 450 ((equal "-suspend" arg)
440 (t 451 (let ((tty (cadr (assq (car client) server-ttys))))
441 ;; Undo the quoting that emacsclient does 452 (setq dontkill t)
442 ;; for certain special characters. 453 (when tty (suspend-tty tty))))
443 (setq arg (server-unquote-arg arg)) 454
444 ;; Now decode the file name if necessary. 455 ;; Noop; useful for debugging emacsclient.
445 (if coding-system 456 ((and (equal "-ignore" arg) (string-match "\\([^ ]*\\) " request))
446 (setq arg (decode-coding-string arg coding-system))) 457 (setq dontkill t
447 (unless version-checked 458 request (substring request (match-end 0))))
448 (error "Protocol error; make sure to use the correct version of emacsclient")) 459
449 (if eval 460 ;; Open a new tty frame at the client. ARG is the name of the pseudo tty.
450 ;; ARG is a Lisp expression. 461 ((and (equal "-tty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
451 (let ((v (eval (car (read-from-string arg))))) 462 (let ((tty (server-unquote-arg (match-string 1 request)))
463 (type (server-unquote-arg (match-string 2 request))))
464 (setq request (substring request (match-end 0)))
465 (unless version-checked
466 (error "Protocol error; make sure to use the correct version of emacsclient"))
467 (let ((frame (make-frame-on-tty tty type)))
468 (push (list (car client) (frame-tty-name frame)) server-ttys)
469 (process-send-string proc (concat "-emacs-pid " (number-to-string (emacs-pid)) "\n"))
470 (select-frame frame)
471 ;; This makes sure that `emacsclient -t -e '(delete-frame)'' works right.
472 (push client server-clients)
473 (setq registered t
474 dontkill t
475 newframe t))))
476
477 ;; ARG is a line number option.
478 ((and (equal "-position" arg) (string-match "\\(\\+[0-9]+\\) " request))
479 (setq request (substring request (match-end 0))
480 lineno (string-to-int (substring (match-string 1 request) 1))))
481
482 ;; ARG is line number:column option.
483 ((and (equal "-position" arg) (string-match "\\+\\([0-9]+\\):\\([0-9]+\\) " request))
484 (setq request (substring request (match-end 0))
485 lineno (string-to-int (match-string 1 request))
486 columnno (string-to-int (match-string 2 request))))
487
488 ;; ARG is a file to load.
489 ((and (equal "-file" arg) (string-match "\\([^ ]+\\) " request))
490 (let ((file (server-unquote-arg (match-string 1 request))))
491 (setq request (substring request (match-end 0)))
492 (if coding-system
493 (setq file (decode-coding-string file coding-system)))
494 (setq file (command-line-normalize-file-name file))
495 (push (list file lineno columnno) files))
496 (setq lineno 1
497 columnno 0))
498
499 ;; ARG is a Lisp expression.
500 ((and (equal "-eval" arg) (string-match "\\([^ ]+\\) " request))
501 (let ((expr (server-unquote-arg (match-string 1 request))))
502 (setq request (substring request (match-end 0)))
503 (if coding-system
504 (setq expr (decode-coding-string expr coding-system)))
505 (let ((v (eval (car (read-from-string expr)))))
452 (when (and (not newframe) v) 506 (when (and (not newframe) v)
453 (with-temp-buffer 507 (with-temp-buffer
454 (let ((standard-output (current-buffer))) 508 (let ((standard-output (current-buffer)))
455 (pp v) 509 (pp v)
456 (process-send-string proc "-print ") 510 (process-send-string proc "-print ")
457 (process-send-region proc (point-min) (point-max)))))) 511 (process-send-string
458 ;; ARG is a file name. 512 proc (server-quote-arg
459 ;; Collapse multiple slashes to single slashes. 513 (buffer-substring-no-properties (point-min)
460 (setq arg (command-line-normalize-file-name arg)) 514 (point-max))))
461 (push (list arg lineno columnno) files)) 515 (process-send-string proc "\n")))))
462 (setq lineno 1) 516 (setq lineno 1
463 (setq columnno 0))))) 517 columnno 0)))
464 518
465 (if (not version-checked) 519 ;; Unknown command.
466 (error "Protocol error; make sure to use the correct version of emacsclient") 520 (t (error "Unknown command: %s" arg)))))
521
467 (when files 522 (when files
468 (run-hooks 'pre-command-hook) 523 (run-hooks 'pre-command-hook)
469 (server-visit-files files client nowait) 524 (server-visit-files files client nowait)
470 (run-hooks 'post-command-hook)) 525 (run-hooks 'post-command-hook))
526
471 ;; CLIENT is now a list (CLIENTNUM BUFFERS...) 527 ;; CLIENT is now a list (CLIENTNUM BUFFERS...)
472 (if (and (not newframe) (null (cdr client))) 528
473 ;; This client is empty; get rid of it immediately. 529 ;; Delete the client if necessary.
474 (progn 530 (cond
475 (delete-process proc) 531 ;; Client requested nowait; return immediately.
476 (server-log "Close empty client" proc)) 532 (nowait
477 ;; We visited some buffer for this client. 533 (delete-process proc)
478 (or nowait registered (push client server-clients)) 534 (server-log "Close nowait client" proc))
479 (unless (or isearch-mode (minibufferp)) 535 ;; This client is empty; get rid of it immediately.
480 (if (and newframe (null (cdr client))) 536 ((and (not dontkill) (null (cdr client)))
481 (message (substitute-command-keys 537 (delete-process proc)
482 "When done with this frame, type \\[delete-frame]")) 538 (server-log "Close empty client" proc))
483 (server-switch-buffer (nth 1 client)) 539 ((not registered)
484 (run-hooks 'server-switch-hook) 540 (push client server-clients)))
485 (unless nowait 541
486 (message (substitute-command-keys 542 ;; We visited some buffer for this client.
487 "When done with a buffer, type \\[server-edit]")))))))) 543 (cond
544 ((or isearch-mode (minibufferp))
545 nil)
546 ((and newframe (null (cdr client)))
547 (message (substitute-command-keys
548 "When done with this frame, type \\[delete-frame]")))
549 ((not (null (cdr client)))
550 (server-switch-buffer (nth 1 client))
551 (run-hooks 'server-switch-hook)
552 (unless nowait
553 (message (substitute-command-keys
554 "When done with a buffer, type \\[server-edit]")))))))
555
488 ;; Save for later any partial line that remains. 556 ;; Save for later any partial line that remains.
489 (when (> (length string) 0) 557 (when (> (length string) 0)
490 (process-put proc 'previous-string string))) 558 (process-put proc 'previous-string string)))
491 ;; condition-case 559 ;; condition-case
492 (error (ignore-errors 560 (error (ignore-errors
493 (process-send-string 561 (process-send-string
494 proc (concat "-error " (error-message-string err))) 562 proc (concat "-error " (server-quote-arg (error-message-string err))))
495 (setq string "") 563 (setq string "")
496 (server-log (error-message-string err) proc) 564 (server-log (error-message-string err) proc)
497 (delete-process proc))))) 565 (delete-process proc)))))
diff --git a/lisp/term/x-win.el b/lisp/term/x-win.el
index e09285e86c1..da5ac04a6c9 100644
--- a/lisp/term/x-win.el
+++ b/lisp/term/x-win.el
@@ -2442,11 +2442,7 @@ order until succeed.")
2442 (if res-selection-timeout 2442 (if res-selection-timeout
2443 (setq x-selection-timeout (string-to-number res-selection-timeout)))) 2443 (setq x-selection-timeout (string-to-number res-selection-timeout))))
2444 2444
2445 ;; XXX This is wrong in general with multi-tty support. 2445 ;; Don't let Emacs suspend under X.
2446 (substitute-key-definition 'suspend-emacs 'iconify-or-deiconify-frame
2447 global-map)
2448
2449 ;; XXX This is wrong in general with multi-tty support.
2450 (add-hook 'suspend-hook 'x-win-suspend-error) 2446 (add-hook 'suspend-hook 'x-win-suspend-error)
2451 2447
2452 ;; Arrange for the kill and yank functions to set and check the clipboard. 2448 ;; Arrange for the kill and yank functions to set and check the clipboard.