Now on revision 113425. ------------------------------------------------------------ revno: 113425 committer: Paul Eggert branch nick: trunk timestamp: Sun 2013-07-14 19:56:17 -0700 message: * callproc.c (Fcall_process_region): Fix minor race and tune. (create_temp_file): New function, with the temp-file-creation part of the old Fcall_process_region. Use Fcopy_sequence to create the temp file name, rather than alloca + build_string, for simplicity. Don't bother to block input around the temp file creation; shouldn't be needed. Simplify use of mktemp. Use record_unwind_protect immediately after creating the temp file; this closes an unlikely race where the temp file was not removed. Use memcpy rather than an open-coded loop. (Fcall_process_region): Use the new function. If the input is empty, redirect from /dev/null rather than from a newly created empty temp file; this avoids unnecessary file system traffic. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-07-14 23:12:42 +0000 +++ src/ChangeLog 2013-07-15 02:56:17 +0000 @@ -1,3 +1,18 @@ +2013-07-15 Paul Eggert + + * callproc.c (Fcall_process_region): Fix minor race and tune. + (create_temp_file): New function, with the temp-file-creation part + of the old Fcall_process_region. Use Fcopy_sequence to create the + temp file name, rather than alloca + build_string, for simplicity. + Don't bother to block input around the temp file creation; + shouldn't be needed. Simplify use of mktemp. Use + record_unwind_protect immediately after creating the temp file; + this closes an unlikely race where the temp file was not removed. + Use memcpy rather than an open-coded loop. + (Fcall_process_region): Use the new function. If the input is + empty, redirect from /dev/null rather than from a newly created + empty temp file; this avoids unnecessary file system traffic. + 2013-07-14 Paul Eggert * filelock.c (create_lock_file) [!HAVE_MKOSTEMP && !HAVE_MKSTEMP]: === modified file 'src/callproc.c' --- src/callproc.c 2013-07-14 00:30:45 +0000 +++ src/callproc.c 2013-07-15 02:56:17 +0000 @@ -960,41 +960,16 @@ return Qnil; } -DEFUN ("call-process-region", Fcall_process_region, Scall_process_region, - 3, MANY, 0, - doc: /* Send text from START to END to a synchronous process running PROGRAM. -The remaining arguments are optional. -Delete the text if fourth arg DELETE is non-nil. - -Insert output in BUFFER before point; t means current buffer; nil for - BUFFER means discard it; 0 means discard and don't wait; and `(:file - FILE)', where FILE is a file name string, means that it should be - written to that file (if the file already exists it is overwritten). -BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, -REAL-BUFFER says what to do with standard output, as above, -while STDERR-FILE says what to do with standard error in the child. -STDERR-FILE may be nil (discard standard error output), -t (mix it with ordinary output), or a file name string. - -Sixth arg DISPLAY non-nil means redisplay buffer as output is inserted. -Remaining args are passed to PROGRAM at startup as command args. - -If BUFFER is 0, `call-process-region' returns immediately with value nil. -Otherwise it waits for PROGRAM to terminate -and returns a numeric exit status or a signal description string. -If you quit, the process is killed with SIGINT, or SIGKILL if you quit again. - -usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS) */) - (ptrdiff_t nargs, Lisp_Object *args) +/* Create a temporary file suitable for storing the input data of + call-process-region. NARGS and ARGS are the same as for + call-process-region. */ + +static Lisp_Object +create_temp_file (ptrdiff_t nargs, Lisp_Object *args) { struct gcpro gcpro1; Lisp_Object filename_string; - register Lisp_Object start, end; - ptrdiff_t count = SPECPDL_INDEX (); - /* Qt denotes we have not yet called Ffind_operation_coding_system. */ - Lisp_Object coding_systems; - Lisp_Object val, *args2; - ptrdiff_t i; + Lisp_Object val, start, end; Lisp_Object tmpdir; if (STRINGP (Vtemporary_file_directory)) @@ -1016,9 +991,7 @@ } { - USE_SAFE_ALLOCA; Lisp_Object pattern = Fexpand_file_name (Vtemp_file_name_pattern, tmpdir); - Lisp_Object encoded_tem; char *tempfile; #ifdef WINDOWSNT @@ -1036,39 +1009,30 @@ } #endif - encoded_tem = ENCODE_FILE (pattern); - tempfile = SAFE_ALLOCA (SBYTES (encoded_tem) + 1); - memcpy (tempfile, SDATA (encoded_tem), SBYTES (encoded_tem) + 1); - coding_systems = Qt; + filename_string = Fcopy_sequence (ENCODE_FILE (pattern)); + GCPRO1 (filename_string); + tempfile = SSDATA (filename_string); -#if defined HAVE_MKOSTEMP || defined HAVE_MKSTEMP { - int fd, open_errno; + int fd; - block_input (); -# ifdef HAVE_MKOSTEMP +#ifdef HAVE_MKOSTEMP fd = mkostemp (tempfile, O_CLOEXEC); -# else +#elif defined HAVE_MKSTEMP fd = mkstemp (tempfile); -# endif - open_errno = errno; - unblock_input (); +#else + errno = EEXIST; + mktemp (tempfile); + /* INT_MAX denotes success, because close (INT_MAX) does nothing. */ + fd = *tempfile ? INT_MAX : -1; +#endif if (fd < 0) - report_file_errno ("Failed to open temporary file", - Fcons (build_string (tempfile), Qnil), open_errno); + report_file_error ("Failed to open temporary file using pattern", + Fcons (pattern, Qnil)); emacs_close (fd); } -#else - errno = EEXIST; - mktemp (tempfile); - if (!*tempfile) - report_file_error ("Failed to open temporary file using pattern", - Fcons (pattern, Qnil)); -#endif - filename_string = build_string (tempfile); - GCPRO1 (filename_string); - SAFE_FREE (); + record_unwind_protect (delete_temp_file, filename_string); } start = args[0]; @@ -1080,10 +1044,12 @@ val = Qraw_text; else { + Lisp_Object coding_systems; + Lisp_Object *args2; USE_SAFE_ALLOCA; SAFE_NALLOCA (args2, 1, nargs + 1); args2[0] = Qcall_process_region; - for (i = 0; i < nargs; i++) args2[i + 1] = args[i]; + memcpy (args2 + 1, args, nargs * sizeof *args); coding_systems = Ffind_operation_coding_system (nargs + 1, args2); val = CONSP (coding_systems) ? XCDR (coding_systems) : Qnil; SAFE_FREE (); @@ -1105,7 +1071,59 @@ /* Note that Fcall_process takes care of binding coding-system-for-read. */ - record_unwind_protect (delete_temp_file, filename_string); + RETURN_UNGCPRO (filename_string); +} + +DEFUN ("call-process-region", Fcall_process_region, Scall_process_region, + 3, MANY, 0, + doc: /* Send text from START to END to a synchronous process running PROGRAM. +The remaining arguments are optional. +Delete the text if fourth arg DELETE is non-nil. + +Insert output in BUFFER before point; t means current buffer; nil for + BUFFER means discard it; 0 means discard and don't wait; and `(:file + FILE)', where FILE is a file name string, means that it should be + written to that file (if the file already exists it is overwritten). +BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, +REAL-BUFFER says what to do with standard output, as above, +while STDERR-FILE says what to do with standard error in the child. +STDERR-FILE may be nil (discard standard error output), +t (mix it with ordinary output), or a file name string. + +Sixth arg DISPLAY non-nil means redisplay buffer as output is inserted. +Remaining args are passed to PROGRAM at startup as command args. + +If BUFFER is 0, `call-process-region' returns immediately with value nil. +Otherwise it waits for PROGRAM to terminate +and returns a numeric exit status or a signal description string. +If you quit, the process is killed with SIGINT, or SIGKILL if you quit again. + +usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS) */) + (ptrdiff_t nargs, Lisp_Object *args) +{ + struct gcpro gcpro1; + Lisp_Object filename_string; + ptrdiff_t count = SPECPDL_INDEX (); + Lisp_Object start = args[0]; + Lisp_Object end = args[1]; + bool empty_input; + + if (STRINGP (start)) + empty_input = SCHARS (start) == 0; + else if (NILP (start)) + empty_input = BEG == Z; + else + { + validate_region (&args[0], &args[1]); + start = args[0]; + end = args[1]; + empty_input = XINT (start) == XINT (end); + } + + filename_string = (empty_input + ? build_string (NULL_DEVICE) + : create_temp_file (nargs, args)); + GCPRO1 (filename_string); if (nargs > 3 && !NILP (args[3])) Fdelete_region (start, end); ------------------------------------------------------------ revno: 113424 committer: Paul Eggert branch nick: trunk timestamp: Sun 2013-07-14 19:33:54 -0700 message: * shell.el (explicit-bash-args): Remove obsolete hack for Bash 1.x. The hack didn't work outside English locales anyway. diff: === modified file 'etc/NEWS' --- etc/NEWS 2013-07-15 00:07:51 +0000 +++ etc/NEWS 2013-07-15 02:33:54 +0000 @@ -456,6 +456,13 @@ *** The Info-edit command is obsolete. Editing Info nodes by hand has not been relevant for some time. +** Shell + +*** `explicit-bash-args' now always defaults to use --noediting. +During initialization, Emacs no longer expends a process to decide +whether it is safe to use Bash's --noediting option. These days +--noediting is ubiquitous; it was introduced in 1996 in Bash version 2. + * New Modes and Packages in Emacs 24.4 === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-07-15 00:49:22 +0000 +++ lisp/ChangeLog 2013-07-15 02:33:54 +0000 @@ -1,3 +1,8 @@ +2013-07-15 Paul Eggert + + * shell.el (explicit-bash-args): Remove obsolete hack for Bash 1.x. + The hack didn't work outside English locales anyway. + 2013-07-15 Juanma Barranquero * simple.el (define-alternatives): Rename from alternatives-define, === modified file 'lisp/shell.el' --- lisp/shell.el 2013-05-15 23:55:41 +0000 +++ lisp/shell.el 2013-07-15 02:33:54 +0000 @@ -284,21 +284,9 @@ ;; Note: There are no explicit references to the variable `explicit-bash-args'. ;; It is used implicitly by M-x shell when the interactive shell is `bash'. (defcustom explicit-bash-args - (let* ((prog (or (and (boundp 'explicit-shell-file-name) explicit-shell-file-name) - (getenv "ESHELL") shell-file-name)) - (name (file-name-nondirectory prog))) - ;; Tell bash not to use readline, except for bash 1.x which - ;; doesn't grok --noediting. Bash 1.x has -nolineediting, but - ;; process-send-eof cannot terminate bash if we use it. - (if (and (not purify-flag) - (equal name "bash") - (file-executable-p prog) - (string-match "bad option" - (shell-command-to-string - (concat (shell-quote-argument prog) - " --noediting")))) - '("-i") - '("--noediting" "-i"))) + ;; Tell bash not to use readline. It's safe to assume --noediting now, + ;; as it was introduced in 1996 in Bash version 2. + '("--noediting" "-i") "Args passed to inferior shell by \\[shell], if the shell is bash. Value is a list of strings, which may be nil." :type '(repeat (string :tag "Argument")) ------------------------------------------------------------ revno: 113423 committer: Juanma Barranquero branch nick: trunk timestamp: Mon 2013-07-15 02:49:22 +0200 message: lisp/simple.el (define-alternatives): Rename from alternatives-define. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-07-15 00:07:51 +0000 +++ lisp/ChangeLog 2013-07-15 00:49:22 +0000 @@ -1,3 +1,8 @@ +2013-07-15 Juanma Barranquero + + * simple.el (define-alternatives): Rename from alternatives-define, + per RMS' suggestion. + 2013-07-14 Juanma Barranquero * desktop.el (desktop-restore-frames): Change default to t. === modified file 'lisp/simple.el' --- lisp/simple.el 2013-07-13 07:26:43 +0000 +++ lisp/simple.el 2013-07-15 00:49:22 +0000 @@ -7437,19 +7437,19 @@ ;;; Generic dispatcher commands -;; Macro `alternatives-define' is used to create generic commands. +;; Macro `define-alternatives' is used to create generic commands. ;; Generic commands are these (like web, mail, news, encrypt, irc, etc.) ;; that can have different alternative implementations where choosing ;; among them is exclusively a matter of user preference. -;; (alternatives-define COMMAND) creates a new interactive command +;; (define-alternatives COMMAND) creates a new interactive command ;; M-x COMMAND and a customizable variable COMMAND-alternatives. ;; Typically, the user will not need to customize this variable; packages ;; wanting to add alternative implementations should use ;; ;; ;;;###autoload (push '("My impl name" . my-impl-symbol) COMMAND-alternatives -(defmacro alternatives-define (command &rest customizations) +(defmacro define-alternatives (command &rest customizations) "Define new command `COMMAND'. The variable `COMMAND-alternatives' will contain alternative implementations of COMMAND, so that running `C-u M-x COMMAND' ------------------------------------------------------------ revno: 113422 committer: Juanma Barranquero branch nick: trunk timestamp: Mon 2013-07-15 02:07:51 +0200 message: lisp/desktop.el (desktop-restore-frames): Change default to t. (desktop-restore-in-current-display): Now offer more options. (desktop-restoring-reuses-frames): New customization option. (desktop--saved-states): Doc fix. (desktop-filter-parameters-alist): New variable, renamed and expanded from desktop--excluded-frame-parameters. (desktop--target-display): New variable. (desktop-switch-to-gui-p, desktop-switch-to-tty-p, desktop--filter-tty*) (desktop--filter-*-color, desktop--filter-minibuffer) (desktop--filter-restore-desktop-parm, desktop--filter-save-desktop-parm) (desktop-restore-in-original-display-p): New functions. (desktop--filter-frame-parms): Use new desktop-filter-parameters-alist. (desktop--save-minibuffer-frames): New function, inspired by a similar function from Martin Rudalics. (desktop--save-frames): Call it; play nice with desktop-globals-to-save. (desktop--restore-in-this-display-p): Remove. (desktop--find-frame): Rename from desktop--find-frame-in-display and add predicate argument. (desktop--make-full-frame): Remove, integrated into desktop--make-frame. (desktop--reuse-list): New variable. (desktop--select-frame, desktop--make-frame, desktop--sort-states): New functions. (desktop--restore-frames): Add support for "minibuffer-special" frames. diff: === modified file 'etc/NEWS' --- etc/NEWS 2013-07-13 10:55:21 +0000 +++ etc/NEWS 2013-07-15 00:07:51 +0000 @@ -255,8 +255,10 @@ *** `desktop-auto-save-timeout' defines the number of seconds between auto-saves of the desktop. -*** `desktop-restore-frames' enables saving and restoring the window/frame -configuration. +*** `desktop-restore-frames', enabled by default, allows saving and +restoring the window/frame configuration. Additional options +`desktop-restore-in-current-display' and +`desktop-restoring-reuses-frames' allow further customization. ** Dired === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-07-14 18:45:50 +0000 +++ lisp/ChangeLog 2013-07-15 00:07:51 +0000 @@ -1,3 +1,30 @@ +2013-07-14 Juanma Barranquero + + * desktop.el (desktop-restore-frames): Change default to t. + (desktop-restore-in-current-display): Now offer more options. + (desktop-restoring-reuses-frames): New customization option. + (desktop--saved-states): Doc fix. + (desktop-filter-parameters-alist): New variable, renamed and expanded + from desktop--excluded-frame-parameters. + (desktop--target-display): New variable. + (desktop-switch-to-gui-p, desktop-switch-to-tty-p) + (desktop--filter-tty*, desktop--filter-*-color) + (desktop--filter-minibuffer, desktop--filter-restore-desktop-parm) + (desktop--filter-save-desktop-parm) + (desktop-restore-in-original-display-p): New functions. + (desktop--filter-frame-parms): Use new desktop-filter-parameters-alist. + (desktop--save-minibuffer-frames): New function, inspired by a similar + function from Martin Rudalics. + (desktop--save-frames): Call it; play nice with desktop-globals-to-save. + (desktop--restore-in-this-display-p): Remove. + (desktop--find-frame): Rename from desktop--find-frame-in-display + and add predicate argument. + (desktop--make-full-frame): Remove, integrated into desktop--make-frame. + (desktop--reuse-list): New variable. + (desktop--select-frame, desktop--make-frame, desktop--sort-states): + New functions. + (desktop--restore-frames): Add support for "minibuffer-special" frames. + 2013-07-14 Michael Albinus * net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'. === modified file 'lisp/desktop.el' --- lisp/desktop.el 2013-07-12 11:21:01 +0000 +++ lisp/desktop.el 2013-07-15 00:07:51 +0000 @@ -33,6 +33,7 @@ ;; - the mark & mark-active ;; - buffer-read-only ;; - some local variables +;; - frame and window configuration ;; To use this, use customize to turn on desktop-save-mode or add the ;; following line somewhere in your init file: @@ -127,7 +128,6 @@ ;; --------------------------------------------------------------------------- ;; TODO: ;; -;; Save window configuration. ;; Recognize more minor modes. ;; Save mark rings. @@ -369,16 +369,29 @@ :type '(repeat symbol) :group 'desktop) -(defcustom desktop-restore-frames nil +(defcustom desktop-restore-frames t "When non-nil, save window/frame configuration to desktop file." :type 'boolean :group 'desktop :version "24.4") (defcustom desktop-restore-in-current-display nil - "When non-nil, frames are restored in the current display. -Otherwise they are restored, if possible, in their original displays." - :type 'boolean + "If t, frames are restored in the current display. +If nil, frames are restored, if possible, in their original displays. +If `delete', frames on other displays are deleted instead of restored." + :type '(choice (const :tag "Restore in current display" t) + (const :tag "Restore in original display" nil) + (const :tag "Delete frames in other displays" 'delete)) + :group 'desktop + :version "24.4") + +(defcustom desktop-restoring-reuses-frames t + "If t, restoring frames reuses existing frames. +If nil, existing frames are deleted. +If `keep', existing frames are kept and not reused." + :type '(choice (const :tag "Reuse existing frames" t) + (const :tag "Delete existing frames" nil) + (const :tag "Keep existing frames" 'keep)) :group 'desktop :version "24.4") @@ -566,7 +579,7 @@ Used to avoid writing contents unchanged between auto-saves.") (defvar desktop--saved-states nil - "Internal use only.") + "Saved window/frame state. Internal use only.") ;; ---------------------------------------------------------------------------- ;; Desktop file conflict detection @@ -869,30 +882,193 @@ ;; ---------------------------------------------------------------------------- -(defconst desktop--excluded-frame-parameters - '(buffer-list - buffer-predicate - buried-buffer-list - explicit-name - font - font-backend - minibuffer - name - outer-window-id - parent-id - window-id - window-system) - "Frame parameters not saved or restored.") - -(defun desktop--filter-frame-parms (frame) - "Return frame parameters of FRAME. -Parameters in `desktop--excluded-frame-parameters' are excluded. +(defvar desktop-filter-parameters-alist + '((background-color . desktop--filter-*-color) + (buffer-list . t) + (buffer-predicate . t) + (buried-buffer-list . t) + (desktop-font . desktop--filter-restore-desktop-parm) + (desktop-fullscreen . desktop--filter-restore-desktop-parm) + (desktop-height . desktop--filter-restore-desktop-parm) + (desktop-width . desktop--filter-restore-desktop-parm) + (font . desktop--filter-save-desktop-parm) + (font-backend . t) + (foreground-color . desktop--filter-*-color) + (fullscreen . desktop--filter-save-desktop-parm) + (height . desktop--filter-save-desktop-parm) + (minibuffer . desktop--filter-minibuffer) + (name . t) + (outer-window-id . t) + (parent-id . t) + (tty . desktop--filter-tty*) + (tty-type . desktop--filter-tty*) + (width . desktop--filter-save-desktop-parm) + (window-id . t) + (window-system . t)) + "Alist of frame parameters and filtering functions. + +Each element is a cons (PARAM . FILTER), where PARAM is a parameter +name (a symbol identifying a frame parameter), and FILTER can be t +\(meaning the parameter is removed from the parameter list on saving +and restoring), or a function that will be called with three args: + + CURRENT a cons (PARAM . VALUE), where PARAM is the one being + filtered and VALUE is its current value + PARAMETERS the complete alist of parameters being filtered + SAVING non-nil if filtering before saving state, nil otherwise + +The FILTER function must return: + nil CURRENT is removed from the list + t CURRENT is left as is + (PARAM' . VALUE') replace CURRENT with this + +Frame parameters not on this list are passed intact.") + +(defvar desktop--target-display nil + "Either (minibuffer . VALUE) or nil. +This refers to the current frame config being processed inside +`frame--restore-frames' and its auxiliary functions (like filtering). +If nil, there is no need to change the display. +If non-nil, display parameter to use when creating the frame. +Internal use only.") + +(defun desktop-switch-to-gui-p (parameters) + "True when switching to a graphic display. +Return t if PARAMETERS describes a text-only terminal and +the target is a graphic display; otherwise return nil. +Only meaningful when called from a filtering function in +`desktop-filter-parameters-alist'." + (and desktop--target-display ; we're switching + (null (cdr (assq 'display parameters))) ; from a tty + (cdr desktop--target-display))) ; to a GUI display + +(defun desktop-switch-to-tty-p (parameters) + "True when switching to a text-only terminal. +Return t if PARAMETERS describes a graphic display and +the target is a text-only terminal; otherwise return nil. +Only meaningful when called from a filtering function in +`desktop-filter-parameters-alist'." + (and desktop--target-display ; we're switching + (cdr (assq 'display parameters)) ; from a GUI display + (null (cdr desktop--target-display)))) ; to a tty + +(defun desktop--filter-tty* (_current parameters saving) + ;; Remove tty and tty-type parameters when switching + ;; to a GUI frame. + (or saving + (not (desktop-switch-to-gui-p parameters)))) + +(defun desktop--filter-*-color (current parameters saving) + ;; Remove (foreground|background)-color parameters + ;; when switching to a GUI frame if they denote an + ;; "unspecified" color. + (or saving + (not (desktop-switch-to-gui-p parameters)) + (not (stringp (cdr current))) + (not (string-match-p "^unspecified-[fb]g$" (cdr current))))) + +(defun desktop--filter-minibuffer (current _parameters saving) + ;; When minibuffer is a window, save it as minibuffer . t + (or (not saving) + (if (windowp (cdr current)) + '(minibuffer . t) + t))) + +(defun desktop--filter-restore-desktop-parm (current parameters saving) + ;; When switching to a GUI frame, convert desktop-XXX parameter to XXX + (or saving + (not (desktop-switch-to-gui-p parameters)) + (let ((val (cdr current))) + (if (eq val :desktop-processed) + nil + (cons (intern (substring (symbol-name (car current)) + 8)) ;; (length "desktop-") + val))))) + +(defun desktop--filter-save-desktop-parm (current parameters saving) + ;; When switching to a tty frame, save parameter XXX as desktop-XXX so it + ;; can be restored in a subsequent GUI session, unless it already exists. + (cond (saving t) + ((desktop-switch-to-tty-p parameters) + (let ((sym (intern (format "desktop-%s" (car current))))) + (if (assq sym parameters) + nil + (cons sym (cdr current))))) + ((desktop-switch-to-gui-p parameters) + (let* ((dtp (assq (intern (format "desktop-%s" (car current))) + parameters)) + (val (cdr dtp))) + (if (eq val :desktop-processed) + nil + (setcdr dtp :desktop-processed) + (cons (car current) val)))) + (t t))) + +(defun desktop-restore-in-original-display-p () + "True if saved frames' displays should be honored." + (cond ((daemonp) t) + ((eq system-type 'windows-nt) nil) + (t (null desktop-restore-in-current-display)))) + +(defun desktop--filter-frame-parms (parameters saving) + "Filter frame parameters and return filtered list. +PARAMETERS is a parameter alist as returned by `frame-parameters'. +If SAVING is non-nil, filtering is happening before saving frame state; +otherwise, filtering is being done before restoring frame state. +Parameters are filtered according to the setting of +`desktop-filter-parameters-alist' (which see). Internal use only." - (let (params) - (dolist (param (frame-parameters frame)) - (unless (memq (car param) desktop--excluded-frame-parameters) - (push param params))) - params)) + (let ((filtered nil)) + (dolist (param parameters) + (let ((filter (cdr (assq (car param) desktop-filter-parameters-alist))) + this) + (cond (;; no filter: pass param + (null filter) + (push param filtered)) + (;; filter = t; skip param + (eq filter t)) + (;; filter func returns nil: skip param + (null (setq this (funcall filter param parameters saving)))) + (;; filter func returns t: pass param + (eq this t) + (push param filtered)) + (;; filter func returns a new param: use it + t + (push this filtered))))) + ;; Set the display parameter after filtering, so that filter functions + ;; have access to its original value. + (when desktop--target-display + (let ((display (assq 'display filtered))) + (if display + (setcdr display (cdr desktop--target-display)) + (push desktop--target-display filtered)))) + filtered)) + +(defun desktop--save-minibuffer-frames () + ;; Adds a desktop-mini parameter to frames + ;; desktop-mini is a list (MINIBUFFER NUMBER DEFAULT?) where + ;; MINIBUFFER t if the frame (including minibuffer-only) owns a minibuffer + ;; NUMBER if MINIBUFFER = t, an ID for the frame; if nil, the ID of + ;; the frame containing the minibuffer used by this frame + ;; DEFAULT? if t, this frame is the value of default-minibuffer-frame + ;; FIXME: What happens with multi-terminal sessions? + (let ((frames (frame-list)) + (count 0)) + ;; Reset desktop-mini for all frames + (dolist (frame frames) + (set-frame-parameter frame 'desktop-mini nil)) + ;; Number all frames with its own minibuffer + (dolist (frame (minibuffer-frame-list)) + (set-frame-parameter frame 'desktop-mini + (list t + (setq count (1+ count)) + (eq frame default-minibuffer-frame)))) + ;; Now link minibufferless frames with their minibuffer frames + (dolist (frame frames) + (unless (frame-parameter frame 'desktop-mini) + (let* ((mb-frame (window-frame (minibuffer-window frame))) + (this (cadr (frame-parameter mb-frame 'desktop-mini)))) + (set-frame-parameter frame 'desktop-mini (list nil this nil))))))) (defun desktop--save-frames () "Save window/frame state, as a global variable. @@ -900,12 +1076,14 @@ Internal use only." (setq desktop--saved-states (and desktop-restore-frames - (mapcar (lambda (frame) - (cons (desktop--filter-frame-parms frame) - (window-state-get (frame-root-window frame) t))) - (cons (selected-frame) - (delq (selected-frame) (frame-list)))))) - (desktop-outvar 'desktop--saved-states)) + (progn + (desktop--save-minibuffer-frames) + (mapcar (lambda (frame) + (cons (desktop--filter-frame-parms (frame-parameters frame) t) + (window-state-get (frame-root-window frame) t))) + (frame-list))))) + (unless (memq 'desktop--saved-states desktop-globals-to-save) + (desktop-outvar 'desktop--saved-states))) ;;;###autoload (defun desktop-save (dirname &optional release auto-save) @@ -1006,71 +1184,220 @@ (defvar desktop-lazy-timer nil) ;; ---------------------------------------------------------------------------- -(defun desktop--restore-in-this-display-p () - (or desktop-restore-in-current-display - (and (eq system-type 'windows-nt) (not (display-graphic-p))))) - -(defun desktop--find-frame-in-display (frames display) - (let (result) - (while (and frames (not result)) - (if (equal display (frame-parameter (car frames) 'display)) - (setq result (car frames)) - (setq frames (cdr frames)))) - result)) - -(defun desktop--make-full-frame (full display config) - (let ((width (and (eq full 'fullheight) (cdr (assq 'width config)))) - (height (and (eq full 'fullwidth) (cdr (assq 'height config)))) - (params '((visibility))) +(defvar desktop--reuse-list nil + "Internal use only.") + +(defun desktop--find-frame (predicate display &rest args) + "Find a suitable frame in `desktop--reuse-list'. +Look through frames whose display property matches DISPLAY and +return the first one for which (PREDICATE frame ARGS) returns t. +If PREDICATE is nil, it is always satisfied. Internal use only. +This is an auxiliary function for `desktop--select-frame'." + (catch :found + (dolist (frame desktop--reuse-list) + (when (and (equal (frame-parameter frame 'display) display) + (or (null predicate) + (apply predicate frame args))) + (throw :found frame))) + nil)) + +(defun desktop--select-frame (display frame-cfg) + "Look for an existing frame to reuse. +DISPLAY is the display where the frame will be shown, and FRAME-CFG +is the parameter list of the frame being restored. Internal use only." + (if (eq desktop-restoring-reuses-frames t) + (let ((frame nil) + mini) + ;; There are no fancy heuristics there. We could implement some + ;; based on frame size and/or position, etc., but it is not clear + ;; that any "gain" (in the sense of reduced flickering, etc.) is + ;; worth the added complexity. In fact, the code below mainly + ;; tries to work nicely when M-x desktop-read is used after a desktop + ;; session has already been loaded. The other main use case, which + ;; is the initial desktop-read upon starting Emacs, should usually + ;; only have one, or very few, frame(s) to reuse. + (cond (;; When the target is tty, every existing frame is reusable. + (null display) + (setq frame (desktop--find-frame nil display))) + (;; If the frame has its own minibuffer, let's see whether + ;; that frame has already been loaded (which can happen after + ;; M-x desktop-read). + (car (setq mini (cdr (assq 'desktop-mini frame-cfg)))) + (setq frame (or (desktop--find-frame + (lambda (f m) + (equal (frame-parameter f 'desktop-mini) m)) + display mini)))) + (;; For minibufferless frames, check whether they already exist, + ;; and that they are linked to the right minibuffer frame. + mini + (setq frame (desktop--find-frame + (lambda (f n) + (let ((m (frame-parameter f 'desktop-mini))) + (and m + (null (car m)) + (= (cadr m) n) + (equal (cadr (frame-parameter + (window-frame (minibuffer-window f)) + 'desktop-mini)) + n)))) + display (cadr mini)))) + (;; Default to just finding a frame in the same display. + t + (setq frame (desktop--find-frame nil display)))) + ;; If found, remove from the list. + (when frame + (setq desktop--reuse-list (delq frame desktop--reuse-list))) frame) - (when width - (setq params (append `((user-size . t) (width . ,width)) params) - config (assq-delete-all 'height config))) - (when height - (setq params (append `((user-size . t) (height . ,height)) params) - config (assq-delete-all 'width config))) - (setq frame (make-frame-on-display display params)) - (modify-frame-parameters frame config) + nil)) + +(defun desktop--make-frame (frame-cfg window-cfg) + "Set up a frame according to its saved state. +That means either creating a new frame or reusing an existing one. +FRAME-CFG is the parameter list of the new frame; WINDOW-CFG is +its window state. Internal use only." + (let* ((fullscreen (cdr (assq 'fullscreen frame-cfg))) + (lines (assq 'tool-bar-lines frame-cfg)) + (filtered-cfg (desktop--filter-frame-parms frame-cfg nil)) + (display (cdr (assq 'display filtered-cfg))) ;; post-filtering + alt-cfg frame) + + ;; This works around bug#14795 (or feature#14795, if not a bug :-) + (setq filtered-cfg (assq-delete-all 'tool-bar-lines filtered-cfg)) + (push '(tool-bar-lines . 0) filtered-cfg) + + (when fullscreen + ;; Currently Emacs has the limitation that it does not record the size + ;; and position of a frame before maximizing it, so we cannot save & + ;; restore that info. Instead, when restoring, we resort to creating + ;; invisible "fullscreen" frames of default size and then maximizing them + ;; (and making them visible) which at least is somewhat user-friendly + ;; when these frames are later de-maximized. + (let ((width (and (eq fullscreen 'fullheight) (cdr (assq 'width filtered-cfg)))) + (height (and (eq fullscreen 'fullwidth) (cdr (assq 'height filtered-cfg)))) + (visible (assq 'visibility filtered-cfg))) + (dolist (parameter '(visibility fullscreen width height)) + (setq filtered-cfg (assq-delete-all parameter filtered-cfg))) + (when width + (setq filtered-cfg (append `((user-size . t) (width . ,width)) + filtered-cfg))) + (when height + (setq filtered-cfg (append `((user-size . t) (height . ,height)) + filtered-cfg))) + ;; These are parameters to apply after creating/setting the frame. + (push visible alt-cfg) + (push (cons 'fullscreen fullscreen) alt-cfg))) + + ;; Time to select or create a frame an apply the big bunch of parameters + (if (setq frame (desktop--select-frame display filtered-cfg)) + (modify-frame-parameters frame filtered-cfg) + (setq frame (make-frame-on-display display filtered-cfg))) + + ;; Let's give the finishing touches (visibility, tool-bar, maximization). + (when lines (push lines alt-cfg)) + (when alt-cfg (modify-frame-parameters frame alt-cfg)) + ;; Now restore window state. + (window-state-put window-cfg (frame-root-window frame) 'safe) frame)) +(defun desktop--sort-states (state1 state2) + ;; Order: default minibuffer frame + ;; other frames with minibuffer, ascending ID + ;; minibufferless frames, ascending ID + (let ((dm1 (cdr (assq 'desktop-mini (car state1)))) + (dm2 (cdr (assq 'desktop-mini (car state2))))) + (cond ((nth 2 dm1) t) + ((nth 2 dm2) nil) + ((null (car dm2)) t) + ((null (car dm1)) nil) + (t (< (cadr dm1) (cadr dm2)))))) + (defun desktop--restore-frames () "Restore window/frame configuration. Internal use only." (when (and desktop-restore-frames desktop--saved-states) - (let ((frames (frame-list)) - (current (frame-parameter nil 'display)) - (selected nil)) + (let* ((frame-mb-map nil) ;; Alist of frames with their own minibuffer + (visible nil) + (delete-saved (eq desktop-restore-in-current-display 'delete)) + (forcing (not (desktop-restore-in-original-display-p))) + (target (and forcing (cons 'display (frame-parameter nil 'display))))) + + ;; Sorting saved states allows us to easily restore minibuffer-owning frames + ;; before minibufferless ones. + (setq desktop--saved-states (sort desktop--saved-states #'desktop--sort-states)) + ;; Potentially all existing frames are reusable. Later we will decide which ones + ;; to reuse, and how to deal with any leftover. + (setq desktop--reuse-list (frame-list)) + (dolist (state desktop--saved-states) (condition-case err - (let* ((config (car state)) - (display (if (desktop--restore-in-this-display-p) - (setcdr (assq 'display config) current) - (cdr (assq 'display config)))) - (full (cdr (assq 'fullscreen config))) - (frame (and (not full) - (desktop--find-frame-in-display frames display)))) - (cond (full - ;; treat fullscreen/maximized frames specially - (setq frame (desktop--make-full-frame full display config))) - (frame - ;; found a frame in the right display -- reuse - (setq frames (delq frame frames)) - (modify-frame-parameters frame config)) - (t - ;; no frames in the display -- make a new one - (setq frame (make-frame-on-display display config)))) - ;; restore windows - (window-state-put (cdr state) (frame-root-window frame) 'safe) - (unless selected (setq selected frame))) + (let* ((frame-cfg (car state)) + (window-cfg (cdr state)) + (d-mini (cdr (assq 'desktop-mini frame-cfg))) + num frame to-tty) + ;; Only set target if forcing displays and the target display is different. + (if (or (not forcing) + (equal target (or (assq 'display frame-cfg) '(display . nil)))) + (setq desktop--target-display nil) + (setq desktop--target-display target + to-tty (null (cdr target)))) + ;; Time to restore frames and set up their minibuffers as they were. + ;; We only skip a frame (thus deleting it) if either: + ;; - we're switching displays, and the user chose the option to delete, or + ;; - we're switching to tty, and the frame to restore is minibuffer-only. + (unless (and desktop--target-display + (or delete-saved + (and to-tty + (eq (cdr (assq 'minibuffer frame-cfg)) 'only)))) + + ;; Restore minibuffers. Some of this stuff could be done in a filter + ;; function, but it would be messy because restoring minibuffers affects + ;; global state; it's best to do it here than add a bunch of global + ;; variables to pass info back-and-forth to/from the filter function. + (cond + ((null d-mini)) ;; No desktop-mini. Process as normal frame. + (to-tty) ;; Ignore minibuffer stuff and process as normal frame. + ((car d-mini) ;; Frame has its own minibuffer (or it is minibuffer-only). + (setq num (cadr d-mini)) + (when (eq (cdr (assq 'minibuffer frame-cfg)) 'only) + (setq frame-cfg (append '((tool-bar-lines . 0) (menu-bar-lines . 0)) + frame-cfg)))) + (t ;; Frame depends on other frame's minibufer window. + (let ((mb-frame (cdr (assq (cadr d-mini) frame-mb-map)))) + (unless (frame-live-p mb-frame) + (error "Minibuffer frame %s not found" (cadr d-mini))) + (let ((mb-param (assq 'minibuffer frame-cfg)) + (mb-window (minibuffer-window mb-frame))) + (unless (and (window-live-p mb-window) + (window-minibuffer-p mb-window)) + (error "Not a minibuffer window %s" mb-window)) + (if mb-param + (setcdr mb-param mb-window) + (push (cons 'minibuffer mb-window) frame-cfg)))))) + ;; OK, we're ready at last to create (or reuse) a frame and + ;; restore the window config. + (setq frame (desktop--make-frame frame-cfg window-cfg)) + ;; Set default-minibuffer if required. + (when (nth 2 d-mini) (setq default-minibuffer-frame frame)) + ;; Store frame/NUM to assign to minibufferless frames. + (when num (push (cons num frame) frame-mb-map)) + ;; Try to locate at least one visible frame. + (when (and (not visible) (frame-visible-p frame)) + (setq visible frame)))) (error - (message "Error restoring frame: %S" (error-message-string err))))) - (when selected - ;; make sure the original selected frame is visible and selected - (unless (or (frame-parameter selected 'visibility) (daemonp)) - (modify-frame-parameters selected '((visibility . t)))) - (select-frame-set-input-focus selected) - ;; delete any remaining frames - (mapc #'delete-frame frames))))) + (delay-warning 'desktop (error-message-string err) :error)))) + + ;; Delete remaining frames, but do not fail if some resist being deleted. + (unless (eq desktop-restoring-reuses-frames 'keep) + (dolist (frame desktop--reuse-list) + (ignore-errors (delete-frame frame)))) + (setq desktop--reuse-list nil) + ;; Make sure there's at least one visible frame, and select it. + (unless (or visible (daemonp)) + (setq visible (if (frame-live-p default-minibuffer-frame) + default-minibuffer-frame + (car (frame-list)))) + (make-frame-visible visible) + (select-frame-set-input-focus visible))))) ;;;###autoload (defun desktop-read (&optional dirname) ------------------------------------------------------------ revno: 113421 author: Paul Eggert committer: Paul Eggert branch nick: trunk timestamp: Sun 2013-07-14 16:12:42 -0700 message: * filelock.c (create_lock_file) [!HAVE_MKOSTEMP && !HAVE_MKSTEMP]: Simplify by making this case like the other two. This is a bit slower on obsolete hosts, but the extra complexity isn't worth it. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-07-14 00:30:45 +0000 +++ src/ChangeLog 2013-07-14 23:12:42 +0000 @@ -1,5 +1,9 @@ 2013-07-14 Paul Eggert + * filelock.c (create_lock_file) [!HAVE_MKOSTEMP && !HAVE_MKSTEMP]: + Simplify by making this case like the other two. This is a bit + slower on obsolete hosts, but the extra complexity isn't worth it. + * callproc.c (child_setup, relocate_fd) [!DOS_NT]: * process.c (create_process) [!DOS_NT]: Remove now-unnecessary calls to emacs_close. === modified file 'src/filelock.c' --- src/filelock.c 2013-07-09 06:29:29 +0000 +++ src/filelock.c 2013-07-14 23:12:42 +0000 @@ -412,8 +412,6 @@ USE_SAFE_ALLOCA; char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base); int fd; - bool need_fchmod; - mode_t world_readable = S_IRUSR | S_IRGRP | S_IROTH; memcpy (nonce, lfname, lfdirlen); strcpy (nonce + lfdirlen, nonce_base); @@ -421,17 +419,14 @@ /* Prefer mkostemp to mkstemp, as it avoids a window where FD is temporarily open without close-on-exec. */ fd = mkostemp (nonce, O_BINARY | O_CLOEXEC); - need_fchmod = 1; #elif HAVE_MKSTEMP /* Prefer mkstemp to mktemp, as it avoids a race between mktemp and emacs_open. */ fd = mkstemp (nonce); - need_fchmod = 1; #else mktemp (nonce); fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, - world_readable); - need_fchmod = 0; + S_IRUSR | S_IWUSR); #endif if (fd < 0) @@ -445,7 +440,7 @@ lock_info_len = strlen (lock_info_str); err = 0; if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len - || (need_fchmod && fchmod (fd, world_readable) != 0)) + || fchmod (fd, S_IRUSR | S_IRGRP | S_IROTH) != 0) err = errno; /* There is no need to call fsync here, as the contents of the lock file need not survive system crashes. */ ------------------------------------------------------------ revno: 113420 committer: Michael Albinus branch nick: trunk timestamp: Sun 2013-07-14 20:45:50 +0200 message: * net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-07-13 19:10:19 +0000 +++ lisp/ChangeLog 2013-07-14 18:45:50 +0000 @@ -1,3 +1,7 @@ +2013-07-14 Michael Albinus + + * net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'. + 2013-07-13 Dmitry Gutov * progmodes/ruby-mode.el (ruby-font-lock-keywords): Highlight === modified file 'lisp/net/tramp-sh.el' --- lisp/net/tramp-sh.el 2013-07-11 09:52:54 +0000 +++ lisp/net/tramp-sh.el 2013-07-14 18:45:50 +0000 @@ -3334,7 +3334,8 @@ ;; `process-file-side-effects' in order to keep the cache when ;; `process-file' calls appear. (let (process-file-side-effects) - (tramp-run-real-handler 'vc-registered (list file))))))) + (ignore-errors + (tramp-run-real-handler 'vc-registered (list file)))))))) ;;;###tramp-autoload (defun tramp-sh-file-name-handler (operation &rest args) ------------------------------------------------------------ revno: 113419 committer: Paul Eggert branch nick: trunk timestamp: Sat 2013-07-13 22:18:48 -0700 message: Spelling fixes. diff: === modified file 'lisp/gnus/ChangeLog' --- lisp/gnus/ChangeLog 2013-07-10 22:17:07 +0000 +++ lisp/gnus/ChangeLog 2013-07-14 05:18:48 +0000 @@ -143,7 +143,7 @@ 2013-07-02 Lars Magne Ingebrigtsen * gnus-sum.el (gnus-summary-insert-old-articles): - Don't include unexistent messages. + Don't include unexisting messages. 2013-07-02 Lars Magne Ingebrigtsen === modified file 'lisp/gnus/gnus-sum.el' --- lisp/gnus/gnus-sum.el 2013-07-03 04:15:38 +0000 +++ lisp/gnus/gnus-sum.el 2013-07-14 05:18:48 +0000 @@ -1525,7 +1525,7 @@ "Range of seen articles in the current newsgroup.") (defvar gnus-newsgroup-unexist nil - "Range of unexistent articles in the current newsgroup.") + "Range of unexisting articles in the current newsgroup.") (defvar gnus-newsgroup-articles nil "List of articles in the current newsgroup.") === modified file 'lisp/ido.el' --- lisp/ido.el 2013-07-13 04:44:19 +0000 +++ lisp/ido.el 2013-07-14 05:18:48 +0000 @@ -782,7 +782,7 @@ :group 'ido) (defcustom ido-use-virtual-buffers nil - "Specify how vritual buffers should be used. + "Specify how virtual buffers should be used. The value can be one of the following: nil: No virtual buffers are used. === modified file 'lisp/progmodes/cc-engine.el' --- lisp/progmodes/cc-engine.el 2013-07-13 17:45:07 +0000 +++ lisp/progmodes/cc-engine.el 2013-07-14 05:18:48 +0000 @@ -7193,7 +7193,7 @@ ;; uncommon (e.g. some placements of "const" in C++) it's not worth ;; the effort to look for them.) -;;; 2008-04-16: commented out the next form, to allow the function to recognise +;;; 2008-04-16: commented out the next form, to allow the function to recognize ;;; "foo (int bar)" in CC (an implicit type (in class foo) without a semicolon) ;;; as a(n almost complete) declaration, enabling it to be fontified. ;; CASE 13