aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuanma Barranquero2013-07-15 02:07:51 +0200
committerJuanma Barranquero2013-07-15 02:07:51 +0200
commitb958c0ad58a129eca0e65bbdd72a135b5017d4a6 (patch)
tree26a5179f96ea28c995c93b6741ec705ac294f3ac
parent5c97beae62104207d0c9099919c7955c8e6f57fd (diff)
downloademacs-b958c0ad58a129eca0e65bbdd72a135b5017d4a6.tar.gz
emacs-b958c0ad58a129eca0e65bbdd72a135b5017d4a6.zip
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.
-rw-r--r--etc/NEWS6
-rw-r--r--lisp/ChangeLog27
-rw-r--r--lisp/desktop.el507
3 files changed, 448 insertions, 92 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 03174a0137f..548063446ee 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -255,8 +255,10 @@ on the given date.
255*** `desktop-auto-save-timeout' defines the number of seconds between 255*** `desktop-auto-save-timeout' defines the number of seconds between
256auto-saves of the desktop. 256auto-saves of the desktop.
257 257
258*** `desktop-restore-frames' enables saving and restoring the window/frame 258*** `desktop-restore-frames', enabled by default, allows saving and
259configuration. 259restoring the window/frame configuration. Additional options
260`desktop-restore-in-current-display' and
261`desktop-restoring-reuses-frames' allow further customization.
260 262
261** Dired 263** Dired
262 264
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 25d666f8f40..34154551fcd 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,30 @@
12013-07-14 Juanma Barranquero <lekktu@gmail.com>
2
3 * desktop.el (desktop-restore-frames): Change default to t.
4 (desktop-restore-in-current-display): Now offer more options.
5 (desktop-restoring-reuses-frames): New customization option.
6 (desktop--saved-states): Doc fix.
7 (desktop-filter-parameters-alist): New variable, renamed and expanded
8 from desktop--excluded-frame-parameters.
9 (desktop--target-display): New variable.
10 (desktop-switch-to-gui-p, desktop-switch-to-tty-p)
11 (desktop--filter-tty*, desktop--filter-*-color)
12 (desktop--filter-minibuffer, desktop--filter-restore-desktop-parm)
13 (desktop--filter-save-desktop-parm)
14 (desktop-restore-in-original-display-p): New functions.
15 (desktop--filter-frame-parms): Use new desktop-filter-parameters-alist.
16 (desktop--save-minibuffer-frames): New function, inspired by a similar
17 function from Martin Rudalics.
18 (desktop--save-frames): Call it; play nice with desktop-globals-to-save.
19 (desktop--restore-in-this-display-p): Remove.
20 (desktop--find-frame): Rename from desktop--find-frame-in-display
21 and add predicate argument.
22 (desktop--make-full-frame): Remove, integrated into desktop--make-frame.
23 (desktop--reuse-list): New variable.
24 (desktop--select-frame, desktop--make-frame, desktop--sort-states):
25 New functions.
26 (desktop--restore-frames): Add support for "minibuffer-special" frames.
27
12013-07-14 Michael Albinus <michael.albinus@gmx.de> 282013-07-14 Michael Albinus <michael.albinus@gmx.de>
2 29
3 * net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'. 30 * net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'.
diff --git a/lisp/desktop.el b/lisp/desktop.el
index 322b95715a2..c31cbead2b9 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -33,6 +33,7 @@
33;; - the mark & mark-active 33;; - the mark & mark-active
34;; - buffer-read-only 34;; - buffer-read-only
35;; - some local variables 35;; - some local variables
36;; - frame and window configuration
36 37
37;; To use this, use customize to turn on desktop-save-mode or add the 38;; To use this, use customize to turn on desktop-save-mode or add the
38;; following line somewhere in your init file: 39;; following line somewhere in your init file:
@@ -127,7 +128,6 @@
127;; --------------------------------------------------------------------------- 128;; ---------------------------------------------------------------------------
128;; TODO: 129;; TODO:
129;; 130;;
130;; Save window configuration.
131;; Recognize more minor modes. 131;; Recognize more minor modes.
132;; Save mark rings. 132;; Save mark rings.
133 133
@@ -369,16 +369,29 @@ modes are restored automatically; they should not be listed here."
369 :type '(repeat symbol) 369 :type '(repeat symbol)
370 :group 'desktop) 370 :group 'desktop)
371 371
372(defcustom desktop-restore-frames nil 372(defcustom desktop-restore-frames t
373 "When non-nil, save window/frame configuration to desktop file." 373 "When non-nil, save window/frame configuration to desktop file."
374 :type 'boolean 374 :type 'boolean
375 :group 'desktop 375 :group 'desktop
376 :version "24.4") 376 :version "24.4")
377 377
378(defcustom desktop-restore-in-current-display nil 378(defcustom desktop-restore-in-current-display nil
379 "When non-nil, frames are restored in the current display. 379 "If t, frames are restored in the current display.
380Otherwise they are restored, if possible, in their original displays." 380If nil, frames are restored, if possible, in their original displays.
381 :type 'boolean 381If `delete', frames on other displays are deleted instead of restored."
382 :type '(choice (const :tag "Restore in current display" t)
383 (const :tag "Restore in original display" nil)
384 (const :tag "Delete frames in other displays" 'delete))
385 :group 'desktop
386 :version "24.4")
387
388(defcustom desktop-restoring-reuses-frames t
389 "If t, restoring frames reuses existing frames.
390If nil, existing frames are deleted.
391If `keep', existing frames are kept and not reused."
392 :type '(choice (const :tag "Reuse existing frames" t)
393 (const :tag "Delete existing frames" nil)
394 (const :tag "Keep existing frames" 'keep))
382 :group 'desktop 395 :group 'desktop
383 :version "24.4") 396 :version "24.4")
384 397
@@ -566,7 +579,7 @@ DIRNAME omitted or nil means use `desktop-dirname'."
566Used to avoid writing contents unchanged between auto-saves.") 579Used to avoid writing contents unchanged between auto-saves.")
567 580
568(defvar desktop--saved-states nil 581(defvar desktop--saved-states nil
569 "Internal use only.") 582 "Saved window/frame state. Internal use only.")
570 583
571;; ---------------------------------------------------------------------------- 584;; ----------------------------------------------------------------------------
572;; Desktop file conflict detection 585;; Desktop file conflict detection
@@ -869,30 +882,193 @@ DIRNAME must be the directory in which the desktop file will be saved."
869 882
870 883
871;; ---------------------------------------------------------------------------- 884;; ----------------------------------------------------------------------------
872(defconst desktop--excluded-frame-parameters 885(defvar desktop-filter-parameters-alist
873 '(buffer-list 886 '((background-color . desktop--filter-*-color)
874 buffer-predicate 887 (buffer-list . t)
875 buried-buffer-list 888 (buffer-predicate . t)
876 explicit-name 889 (buried-buffer-list . t)
877 font 890 (desktop-font . desktop--filter-restore-desktop-parm)
878 font-backend 891 (desktop-fullscreen . desktop--filter-restore-desktop-parm)
879 minibuffer 892 (desktop-height . desktop--filter-restore-desktop-parm)
880 name 893 (desktop-width . desktop--filter-restore-desktop-parm)
881 outer-window-id 894 (font . desktop--filter-save-desktop-parm)
882 parent-id 895 (font-backend . t)
883 window-id 896 (foreground-color . desktop--filter-*-color)
884 window-system) 897 (fullscreen . desktop--filter-save-desktop-parm)
885 "Frame parameters not saved or restored.") 898 (height . desktop--filter-save-desktop-parm)
886 899 (minibuffer . desktop--filter-minibuffer)
887(defun desktop--filter-frame-parms (frame) 900 (name . t)
888 "Return frame parameters of FRAME. 901 (outer-window-id . t)
889Parameters in `desktop--excluded-frame-parameters' are excluded. 902 (parent-id . t)
903 (tty . desktop--filter-tty*)
904 (tty-type . desktop--filter-tty*)
905 (width . desktop--filter-save-desktop-parm)
906 (window-id . t)
907 (window-system . t))
908 "Alist of frame parameters and filtering functions.
909
910Each element is a cons (PARAM . FILTER), where PARAM is a parameter
911name (a symbol identifying a frame parameter), and FILTER can be t
912\(meaning the parameter is removed from the parameter list on saving
913and restoring), or a function that will be called with three args:
914
915 CURRENT a cons (PARAM . VALUE), where PARAM is the one being
916 filtered and VALUE is its current value
917 PARAMETERS the complete alist of parameters being filtered
918 SAVING non-nil if filtering before saving state, nil otherwise
919
920The FILTER function must return:
921 nil CURRENT is removed from the list
922 t CURRENT is left as is
923 (PARAM' . VALUE') replace CURRENT with this
924
925Frame parameters not on this list are passed intact.")
926
927(defvar desktop--target-display nil
928 "Either (minibuffer . VALUE) or nil.
929This refers to the current frame config being processed inside
930`frame--restore-frames' and its auxiliary functions (like filtering).
931If nil, there is no need to change the display.
932If non-nil, display parameter to use when creating the frame.
933Internal use only.")
934
935(defun desktop-switch-to-gui-p (parameters)
936 "True when switching to a graphic display.
937Return t if PARAMETERS describes a text-only terminal and
938the target is a graphic display; otherwise return nil.
939Only meaningful when called from a filtering function in
940`desktop-filter-parameters-alist'."
941 (and desktop--target-display ; we're switching
942 (null (cdr (assq 'display parameters))) ; from a tty
943 (cdr desktop--target-display))) ; to a GUI display
944
945(defun desktop-switch-to-tty-p (parameters)
946 "True when switching to a text-only terminal.
947Return t if PARAMETERS describes a graphic display and
948the target is a text-only terminal; otherwise return nil.
949Only meaningful when called from a filtering function in
950`desktop-filter-parameters-alist'."
951 (and desktop--target-display ; we're switching
952 (cdr (assq 'display parameters)) ; from a GUI display
953 (null (cdr desktop--target-display)))) ; to a tty
954
955(defun desktop--filter-tty* (_current parameters saving)
956 ;; Remove tty and tty-type parameters when switching
957 ;; to a GUI frame.
958 (or saving
959 (not (desktop-switch-to-gui-p parameters))))
960
961(defun desktop--filter-*-color (current parameters saving)
962 ;; Remove (foreground|background)-color parameters
963 ;; when switching to a GUI frame if they denote an
964 ;; "unspecified" color.
965 (or saving
966 (not (desktop-switch-to-gui-p parameters))
967 (not (stringp (cdr current)))
968 (not (string-match-p "^unspecified-[fb]g$" (cdr current)))))
969
970(defun desktop--filter-minibuffer (current _parameters saving)
971 ;; When minibuffer is a window, save it as minibuffer . t
972 (or (not saving)
973 (if (windowp (cdr current))
974 '(minibuffer . t)
975 t)))
976
977(defun desktop--filter-restore-desktop-parm (current parameters saving)
978 ;; When switching to a GUI frame, convert desktop-XXX parameter to XXX
979 (or saving
980 (not (desktop-switch-to-gui-p parameters))
981 (let ((val (cdr current)))
982 (if (eq val :desktop-processed)
983 nil
984 (cons (intern (substring (symbol-name (car current))
985 8)) ;; (length "desktop-")
986 val)))))
987
988(defun desktop--filter-save-desktop-parm (current parameters saving)
989 ;; When switching to a tty frame, save parameter XXX as desktop-XXX so it
990 ;; can be restored in a subsequent GUI session, unless it already exists.
991 (cond (saving t)
992 ((desktop-switch-to-tty-p parameters)
993 (let ((sym (intern (format "desktop-%s" (car current)))))
994 (if (assq sym parameters)
995 nil
996 (cons sym (cdr current)))))
997 ((desktop-switch-to-gui-p parameters)
998 (let* ((dtp (assq (intern (format "desktop-%s" (car current)))
999 parameters))
1000 (val (cdr dtp)))
1001 (if (eq val :desktop-processed)
1002 nil
1003 (setcdr dtp :desktop-processed)
1004 (cons (car current) val))))
1005 (t t)))
1006
1007(defun desktop-restore-in-original-display-p ()
1008 "True if saved frames' displays should be honored."
1009 (cond ((daemonp) t)
1010 ((eq system-type 'windows-nt) nil)
1011 (t (null desktop-restore-in-current-display))))
1012
1013(defun desktop--filter-frame-parms (parameters saving)
1014 "Filter frame parameters and return filtered list.
1015PARAMETERS is a parameter alist as returned by `frame-parameters'.
1016If SAVING is non-nil, filtering is happening before saving frame state;
1017otherwise, filtering is being done before restoring frame state.
1018Parameters are filtered according to the setting of
1019`desktop-filter-parameters-alist' (which see).
890Internal use only." 1020Internal use only."
891 (let (params) 1021 (let ((filtered nil))
892 (dolist (param (frame-parameters frame)) 1022 (dolist (param parameters)
893 (unless (memq (car param) desktop--excluded-frame-parameters) 1023 (let ((filter (cdr (assq (car param) desktop-filter-parameters-alist)))
894 (push param params))) 1024 this)
895 params)) 1025 (cond (;; no filter: pass param
1026 (null filter)
1027 (push param filtered))
1028 (;; filter = t; skip param
1029 (eq filter t))
1030 (;; filter func returns nil: skip param
1031 (null (setq this (funcall filter param parameters saving))))
1032 (;; filter func returns t: pass param
1033 (eq this t)
1034 (push param filtered))
1035 (;; filter func returns a new param: use it
1036 t
1037 (push this filtered)))))
1038 ;; Set the display parameter after filtering, so that filter functions
1039 ;; have access to its original value.
1040 (when desktop--target-display
1041 (let ((display (assq 'display filtered)))
1042 (if display
1043 (setcdr display (cdr desktop--target-display))
1044 (push desktop--target-display filtered))))
1045 filtered))
1046
1047(defun desktop--save-minibuffer-frames ()
1048 ;; Adds a desktop-mini parameter to frames
1049 ;; desktop-mini is a list (MINIBUFFER NUMBER DEFAULT?) where
1050 ;; MINIBUFFER t if the frame (including minibuffer-only) owns a minibuffer
1051 ;; NUMBER if MINIBUFFER = t, an ID for the frame; if nil, the ID of
1052 ;; the frame containing the minibuffer used by this frame
1053 ;; DEFAULT? if t, this frame is the value of default-minibuffer-frame
1054 ;; FIXME: What happens with multi-terminal sessions?
1055 (let ((frames (frame-list))
1056 (count 0))
1057 ;; Reset desktop-mini for all frames
1058 (dolist (frame frames)
1059 (set-frame-parameter frame 'desktop-mini nil))
1060 ;; Number all frames with its own minibuffer
1061 (dolist (frame (minibuffer-frame-list))
1062 (set-frame-parameter frame 'desktop-mini
1063 (list t
1064 (setq count (1+ count))
1065 (eq frame default-minibuffer-frame))))
1066 ;; Now link minibufferless frames with their minibuffer frames
1067 (dolist (frame frames)
1068 (unless (frame-parameter frame 'desktop-mini)
1069 (let* ((mb-frame (window-frame (minibuffer-window frame)))
1070 (this (cadr (frame-parameter mb-frame 'desktop-mini))))
1071 (set-frame-parameter frame 'desktop-mini (list nil this nil)))))))
896 1072
897(defun desktop--save-frames () 1073(defun desktop--save-frames ()
898 "Save window/frame state, as a global variable. 1074 "Save window/frame state, as a global variable.
@@ -900,12 +1076,14 @@ Intended to be called from `desktop-save'.
900Internal use only." 1076Internal use only."
901 (setq desktop--saved-states 1077 (setq desktop--saved-states
902 (and desktop-restore-frames 1078 (and desktop-restore-frames
903 (mapcar (lambda (frame) 1079 (progn
904 (cons (desktop--filter-frame-parms frame) 1080 (desktop--save-minibuffer-frames)
905 (window-state-get (frame-root-window frame) t))) 1081 (mapcar (lambda (frame)
906 (cons (selected-frame) 1082 (cons (desktop--filter-frame-parms (frame-parameters frame) t)
907 (delq (selected-frame) (frame-list)))))) 1083 (window-state-get (frame-root-window frame) t)))
908 (desktop-outvar 'desktop--saved-states)) 1084 (frame-list)))))
1085 (unless (memq 'desktop--saved-states desktop-globals-to-save)
1086 (desktop-outvar 'desktop--saved-states)))
909 1087
910;;;###autoload 1088;;;###autoload
911(defun desktop-save (dirname &optional release auto-save) 1089(defun desktop-save (dirname &optional release auto-save)
@@ -1006,71 +1184,220 @@ This function also sets `desktop-dirname' to nil."
1006(defvar desktop-lazy-timer nil) 1184(defvar desktop-lazy-timer nil)
1007 1185
1008;; ---------------------------------------------------------------------------- 1186;; ----------------------------------------------------------------------------
1009(defun desktop--restore-in-this-display-p () 1187(defvar desktop--reuse-list nil
1010 (or desktop-restore-in-current-display 1188 "Internal use only.")
1011 (and (eq system-type 'windows-nt) (not (display-graphic-p))))) 1189
1012 1190(defun desktop--find-frame (predicate display &rest args)
1013(defun desktop--find-frame-in-display (frames display) 1191 "Find a suitable frame in `desktop--reuse-list'.
1014 (let (result) 1192Look through frames whose display property matches DISPLAY and
1015 (while (and frames (not result)) 1193return the first one for which (PREDICATE frame ARGS) returns t.
1016 (if (equal display (frame-parameter (car frames) 'display)) 1194If PREDICATE is nil, it is always satisfied. Internal use only.
1017 (setq result (car frames)) 1195This is an auxiliary function for `desktop--select-frame'."
1018 (setq frames (cdr frames)))) 1196 (catch :found
1019 result)) 1197 (dolist (frame desktop--reuse-list)
1020 1198 (when (and (equal (frame-parameter frame 'display) display)
1021(defun desktop--make-full-frame (full display config) 1199 (or (null predicate)
1022 (let ((width (and (eq full 'fullheight) (cdr (assq 'width config)))) 1200 (apply predicate frame args)))
1023 (height (and (eq full 'fullwidth) (cdr (assq 'height config)))) 1201 (throw :found frame)))
1024 (params '((visibility))) 1202 nil))
1203
1204(defun desktop--select-frame (display frame-cfg)
1205 "Look for an existing frame to reuse.
1206DISPLAY is the display where the frame will be shown, and FRAME-CFG
1207is the parameter list of the frame being restored. Internal use only."
1208 (if (eq desktop-restoring-reuses-frames t)
1209 (let ((frame nil)
1210 mini)
1211 ;; There are no fancy heuristics there. We could implement some
1212 ;; based on frame size and/or position, etc., but it is not clear
1213 ;; that any "gain" (in the sense of reduced flickering, etc.) is
1214 ;; worth the added complexity. In fact, the code below mainly
1215 ;; tries to work nicely when M-x desktop-read is used after a desktop
1216 ;; session has already been loaded. The other main use case, which
1217 ;; is the initial desktop-read upon starting Emacs, should usually
1218 ;; only have one, or very few, frame(s) to reuse.
1219 (cond (;; When the target is tty, every existing frame is reusable.
1220 (null display)
1221 (setq frame (desktop--find-frame nil display)))
1222 (;; If the frame has its own minibuffer, let's see whether
1223 ;; that frame has already been loaded (which can happen after
1224 ;; M-x desktop-read).
1225 (car (setq mini (cdr (assq 'desktop-mini frame-cfg))))
1226 (setq frame (or (desktop--find-frame
1227 (lambda (f m)
1228 (equal (frame-parameter f 'desktop-mini) m))
1229 display mini))))
1230 (;; For minibufferless frames, check whether they already exist,
1231 ;; and that they are linked to the right minibuffer frame.
1232 mini
1233 (setq frame (desktop--find-frame
1234 (lambda (f n)
1235 (let ((m (frame-parameter f 'desktop-mini)))
1236 (and m
1237 (null (car m))
1238 (= (cadr m) n)
1239 (equal (cadr (frame-parameter
1240 (window-frame (minibuffer-window f))
1241 'desktop-mini))
1242 n))))
1243 display (cadr mini))))
1244 (;; Default to just finding a frame in the same display.
1245 t
1246 (setq frame (desktop--find-frame nil display))))
1247 ;; If found, remove from the list.
1248 (when frame
1249 (setq desktop--reuse-list (delq frame desktop--reuse-list)))
1025 frame) 1250 frame)
1026 (when width 1251 nil))
1027 (setq params (append `((user-size . t) (width . ,width)) params) 1252
1028 config (assq-delete-all 'height config))) 1253(defun desktop--make-frame (frame-cfg window-cfg)
1029 (when height 1254 "Set up a frame according to its saved state.
1030 (setq params (append `((user-size . t) (height . ,height)) params) 1255That means either creating a new frame or reusing an existing one.
1031 config (assq-delete-all 'width config))) 1256FRAME-CFG is the parameter list of the new frame; WINDOW-CFG is
1032 (setq frame (make-frame-on-display display params)) 1257its window state. Internal use only."
1033 (modify-frame-parameters frame config) 1258 (let* ((fullscreen (cdr (assq 'fullscreen frame-cfg)))
1259 (lines (assq 'tool-bar-lines frame-cfg))
1260 (filtered-cfg (desktop--filter-frame-parms frame-cfg nil))
1261 (display (cdr (assq 'display filtered-cfg))) ;; post-filtering
1262 alt-cfg frame)
1263
1264 ;; This works around bug#14795 (or feature#14795, if not a bug :-)
1265 (setq filtered-cfg (assq-delete-all 'tool-bar-lines filtered-cfg))
1266 (push '(tool-bar-lines . 0) filtered-cfg)
1267
1268 (when fullscreen
1269 ;; Currently Emacs has the limitation that it does not record the size
1270 ;; and position of a frame before maximizing it, so we cannot save &
1271 ;; restore that info. Instead, when restoring, we resort to creating
1272 ;; invisible "fullscreen" frames of default size and then maximizing them
1273 ;; (and making them visible) which at least is somewhat user-friendly
1274 ;; when these frames are later de-maximized.
1275 (let ((width (and (eq fullscreen 'fullheight) (cdr (assq 'width filtered-cfg))))
1276 (height (and (eq fullscreen 'fullwidth) (cdr (assq 'height filtered-cfg))))
1277 (visible (assq 'visibility filtered-cfg)))
1278 (dolist (parameter '(visibility fullscreen width height))
1279 (setq filtered-cfg (assq-delete-all parameter filtered-cfg)))
1280 (when width
1281 (setq filtered-cfg (append `((user-size . t) (width . ,width))
1282 filtered-cfg)))
1283 (when height
1284 (setq filtered-cfg (append `((user-size . t) (height . ,height))
1285 filtered-cfg)))
1286 ;; These are parameters to apply after creating/setting the frame.
1287 (push visible alt-cfg)
1288 (push (cons 'fullscreen fullscreen) alt-cfg)))
1289
1290 ;; Time to select or create a frame an apply the big bunch of parameters
1291 (if (setq frame (desktop--select-frame display filtered-cfg))
1292 (modify-frame-parameters frame filtered-cfg)
1293 (setq frame (make-frame-on-display display filtered-cfg)))
1294
1295 ;; Let's give the finishing touches (visibility, tool-bar, maximization).
1296 (when lines (push lines alt-cfg))
1297 (when alt-cfg (modify-frame-parameters frame alt-cfg))
1298 ;; Now restore window state.
1299 (window-state-put window-cfg (frame-root-window frame) 'safe)
1034 frame)) 1300 frame))
1035 1301
1302(defun desktop--sort-states (state1 state2)
1303 ;; Order: default minibuffer frame
1304 ;; other frames with minibuffer, ascending ID
1305 ;; minibufferless frames, ascending ID
1306 (let ((dm1 (cdr (assq 'desktop-mini (car state1))))
1307 (dm2 (cdr (assq 'desktop-mini (car state2)))))
1308 (cond ((nth 2 dm1) t)
1309 ((nth 2 dm2) nil)
1310 ((null (car dm2)) t)
1311 ((null (car dm1)) nil)
1312 (t (< (cadr dm1) (cadr dm2))))))
1313
1036(defun desktop--restore-frames () 1314(defun desktop--restore-frames ()
1037 "Restore window/frame configuration. 1315 "Restore window/frame configuration.
1038Internal use only." 1316Internal use only."
1039 (when (and desktop-restore-frames desktop--saved-states) 1317 (when (and desktop-restore-frames desktop--saved-states)
1040 (let ((frames (frame-list)) 1318 (let* ((frame-mb-map nil) ;; Alist of frames with their own minibuffer
1041 (current (frame-parameter nil 'display)) 1319 (visible nil)
1042 (selected nil)) 1320 (delete-saved (eq desktop-restore-in-current-display 'delete))
1321 (forcing (not (desktop-restore-in-original-display-p)))
1322 (target (and forcing (cons 'display (frame-parameter nil 'display)))))
1323
1324 ;; Sorting saved states allows us to easily restore minibuffer-owning frames
1325 ;; before minibufferless ones.
1326 (setq desktop--saved-states (sort desktop--saved-states #'desktop--sort-states))
1327 ;; Potentially all existing frames are reusable. Later we will decide which ones
1328 ;; to reuse, and how to deal with any leftover.
1329 (setq desktop--reuse-list (frame-list))
1330
1043 (dolist (state desktop--saved-states) 1331 (dolist (state desktop--saved-states)
1044 (condition-case err 1332 (condition-case err
1045 (let* ((config (car state)) 1333 (let* ((frame-cfg (car state))
1046 (display (if (desktop--restore-in-this-display-p) 1334 (window-cfg (cdr state))
1047 (setcdr (assq 'display config) current) 1335 (d-mini (cdr (assq 'desktop-mini frame-cfg)))
1048 (cdr (assq 'display config)))) 1336 num frame to-tty)
1049 (full (cdr (assq 'fullscreen config))) 1337 ;; Only set target if forcing displays and the target display is different.
1050 (frame (and (not full) 1338 (if (or (not forcing)
1051 (desktop--find-frame-in-display frames display)))) 1339 (equal target (or (assq 'display frame-cfg) '(display . nil))))
1052 (cond (full 1340 (setq desktop--target-display nil)
1053 ;; treat fullscreen/maximized frames specially 1341 (setq desktop--target-display target
1054 (setq frame (desktop--make-full-frame full display config))) 1342 to-tty (null (cdr target))))
1055 (frame 1343 ;; Time to restore frames and set up their minibuffers as they were.
1056 ;; found a frame in the right display -- reuse 1344 ;; We only skip a frame (thus deleting it) if either:
1057 (setq frames (delq frame frames)) 1345 ;; - we're switching displays, and the user chose the option to delete, or
1058 (modify-frame-parameters frame config)) 1346 ;; - we're switching to tty, and the frame to restore is minibuffer-only.
1059 (t 1347 (unless (and desktop--target-display
1060 ;; no frames in the display -- make a new one 1348 (or delete-saved
1061 (setq frame (make-frame-on-display display config)))) 1349 (and to-tty
1062 ;; restore windows 1350 (eq (cdr (assq 'minibuffer frame-cfg)) 'only))))
1063 (window-state-put (cdr state) (frame-root-window frame) 'safe) 1351
1064 (unless selected (setq selected frame))) 1352 ;; Restore minibuffers. Some of this stuff could be done in a filter
1353 ;; function, but it would be messy because restoring minibuffers affects
1354 ;; global state; it's best to do it here than add a bunch of global
1355 ;; variables to pass info back-and-forth to/from the filter function.
1356 (cond
1357 ((null d-mini)) ;; No desktop-mini. Process as normal frame.
1358 (to-tty) ;; Ignore minibuffer stuff and process as normal frame.
1359 ((car d-mini) ;; Frame has its own minibuffer (or it is minibuffer-only).
1360 (setq num (cadr d-mini))
1361 (when (eq (cdr (assq 'minibuffer frame-cfg)) 'only)
1362 (setq frame-cfg (append '((tool-bar-lines . 0) (menu-bar-lines . 0))
1363 frame-cfg))))
1364 (t ;; Frame depends on other frame's minibufer window.
1365 (let ((mb-frame (cdr (assq (cadr d-mini) frame-mb-map))))
1366 (unless (frame-live-p mb-frame)
1367 (error "Minibuffer frame %s not found" (cadr d-mini)))
1368 (let ((mb-param (assq 'minibuffer frame-cfg))
1369 (mb-window (minibuffer-window mb-frame)))
1370 (unless (and (window-live-p mb-window)
1371 (window-minibuffer-p mb-window))
1372 (error "Not a minibuffer window %s" mb-window))
1373 (if mb-param
1374 (setcdr mb-param mb-window)
1375 (push (cons 'minibuffer mb-window) frame-cfg))))))
1376 ;; OK, we're ready at last to create (or reuse) a frame and
1377 ;; restore the window config.
1378 (setq frame (desktop--make-frame frame-cfg window-cfg))
1379 ;; Set default-minibuffer if required.
1380 (when (nth 2 d-mini) (setq default-minibuffer-frame frame))
1381 ;; Store frame/NUM to assign to minibufferless frames.
1382 (when num (push (cons num frame) frame-mb-map))
1383 ;; Try to locate at least one visible frame.
1384 (when (and (not visible) (frame-visible-p frame))
1385 (setq visible frame))))
1065 (error 1386 (error
1066 (message "Error restoring frame: %S" (error-message-string err))))) 1387 (delay-warning 'desktop (error-message-string err) :error))))
1067 (when selected 1388
1068 ;; make sure the original selected frame is visible and selected 1389 ;; Delete remaining frames, but do not fail if some resist being deleted.
1069 (unless (or (frame-parameter selected 'visibility) (daemonp)) 1390 (unless (eq desktop-restoring-reuses-frames 'keep)
1070 (modify-frame-parameters selected '((visibility . t)))) 1391 (dolist (frame desktop--reuse-list)
1071 (select-frame-set-input-focus selected) 1392 (ignore-errors (delete-frame frame))))
1072 ;; delete any remaining frames 1393 (setq desktop--reuse-list nil)
1073 (mapc #'delete-frame frames))))) 1394 ;; Make sure there's at least one visible frame, and select it.
1395 (unless (or visible (daemonp))
1396 (setq visible (if (frame-live-p default-minibuffer-frame)
1397 default-minibuffer-frame
1398 (car (frame-list))))
1399 (make-frame-visible visible)
1400 (select-frame-set-input-focus visible)))))
1074 1401
1075;;;###autoload 1402;;;###autoload
1076(defun desktop-read (&optional dirname) 1403(defun desktop-read (&optional dirname)