This is basically the same patch as before, only slightly more polished. It's surprisingly functional for its tiny size. Changes: - Window/frame config is still saved as a global variable, but not from desktop-globals-to-save, which is a user option. - Some frame parameters are not saved, mostly those that cannot be read back or makes no sense to do so. - Errors while restoring the config do not interrupt the restoring; there's just a message afterwards. There are many things still unimplemented, some of which should be discussed before throwing code at it. From the top of my head: 1) When restoring frames, what to do with the existing ones? They can be reused, or deleted. Reusing them will cause less "flicker". 2) What to do with frames with a buffer-predicate? Currently I'm excluding that frame parameter. It could be saved if it is a symbol, of course. 3) What about maximized / fullscreen frames? Currently they don't restore too well. It would be possible, but the original pre-(fullscreen|maximized) size will not be saved. It could be saved by de-maximizing the frame before saving it and then maximizing it back again, but if the user is just calling desktop-save in the middle of a session, that will make the maximized frame flicker. 4) I'm not saving the `minibuffer' parameter, though I should. It's trivial for t/nil/only, but what about minibuffer . <#window...>? Should we try to save/restore that somehow? 5) Presumably, for Emacs on X I should make sure that each frame is restored in the corresponding display. I'm not yet doing that (I don't have a way to test it). All in all, the patch is small and non-intrusive. Perhaps I could install it (with desktop-save-windows defaulting to nil) so people could experiment and say what works and what doesn't. That would be particularly useful from people who use multi-frame setups (Stefan and Drew come to mind). Comments? J === modified file 'lisp/desktop.el' --- lisp/desktop.el 2013-05-02 17:47:39 +0000 +++ lisp/desktop.el 2013-06-26 17:15:07 +0000 @@ -371,6 +371,12 @@ :type '(repeat symbol) :group 'desktop) +(defcustom desktop-save-windows t + "When non-nil, save window/frame configuration to desktop file." + :type 'boolean + :group 'desktop + :version "24.4") + (defcustom desktop-file-name-format 'absolute "Format in which desktop file names should be saved. Possible values are: @@ -556,6 +562,9 @@ "Checksum of the last auto-saved contents of the desktop file. Used to avoid writing contents unchanged between auto-saves.") +(defvar desktop--window-state nil + "Internal use only.") + ;; ---------------------------------------------------------------------------- ;; Desktop file conflict detection (defvar desktop-file-modtime nil @@ -858,6 +867,37 @@ ;; ---------------------------------------------------------------------------- +(defconst desktop--excluded-frame-parameters + '(minibuffer-predicate + minibuffer + buffer-list + buried-buffer-list + window-id + outer-window-id) + "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. +Internal use only." + (let (params) + (dolist (param (frame-parameters frame)) + (unless (memq param desktop--excluded-frame-parameters) + (push param params))) + params)) + +(defun desktop--save-windows () + "Save window/frame state, as a global variable. +Intended to be called from `desktop-save'. +Internal use only." + (setq desktop--window-state + (and desktop-save-windows + (mapcar (lambda (frame) + (cons (desktop--filter-frame-parms frame) + (window-state-get (frame-root-window frame) t))) + (frame-list)))) + (desktop-outvar 'desktop--window-state)) + ;;;###autoload (defun desktop-save (dirname &optional release auto-save) "Save the desktop in a desktop file. @@ -896,6 +936,9 @@ (save-excursion (run-hooks 'desktop-save-hook)) (goto-char (point-max)) (insert "\n;; Global section:\n") + ;; Called here because we save the window/frame state as a global + ;; variable for compatibility with previous Emacsen. + (desktop--save-windows) (mapc (function desktop-outvar) desktop-globals-to-save) (when (memq 'kill-ring desktop-globals-to-save) (insert @@ -954,6 +997,20 @@ (defvar desktop-lazy-timer nil) ;; ---------------------------------------------------------------------------- +(defun desktop--restore-windows () + "Restore window/frame configuration. +Internal use only." + (when (and desktop-save-windows desktop--window-state) + (let ((current (frame-list)) + (failure nil)) + (dolist (state desktop--window-state) + (condition-case nil + (window-state-put (cdr state) (frame-root-window (make-frame (car state)))) + (error (setq failure t)))) + (if failure + (message "Error loading window configuration from desktop file") + (mapc #'delete-frame current))))) + ;;;###autoload (defun desktop-read (&optional dirname) "Read and process the desktop file in directory DIRNAME. @@ -1022,6 +1079,7 @@ (switch-to-buffer (car (buffer-list))) (run-hooks 'desktop-delay-hook) (setq desktop-delay-hook nil) + (desktop--restore-windows) (run-hooks 'desktop-after-read-hook) (message "Desktop: %d buffer%s restored%s%s." desktop-buffer-ok-count