aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuanma Barranquero2013-08-05 00:12:18 +0200
committerJuanma Barranquero2013-08-05 00:12:18 +0200
commitd5671a82b8b78b5fd8d83cfc15642d2c0eff6de2 (patch)
treeb77fc2966aca90b9ac1e72dbd73d86ea652374df
parent016d3f7ddcc9afd60c455cbf4dd79277080c4d4e (diff)
downloademacs-d5671a82b8b78b5fd8d83cfc15642d2c0eff6de2.tar.gz
emacs-d5671a82b8b78b5fd8d83cfc15642d2c0eff6de2.zip
* lisp/frameset.el: Add new predicate values for frameset-restore args.
(frameset-live-filter-alist, frameset-persistent-filter-alist): New variables. (frameset-filter-alist): Use them. Add autoload cookie. (frameset-filter-tty-to-GUI): Move from desktop.el and rename. (frameset--set-id, frameset--reuse-frame): Rename `frame-id' to `frameset--id' (it's supposed to be internal to frameset.el). (frameset--process-minibuffer-frames): Ditto. Doc fix. (frameset--initial-params): New function. (frameset--get-frame): Use it. Doc fix. (frameset--move-onscreen): Accept new PRED value for FORCE-ONSCREEN. Accept :all, not 'all. (frameset-restore): Add new predicate values for FORCE-ONSCREEN and FORCE-DISPLAY. Use :keywords for constant arguments to avoid collision with fbound symbols. Fix frame id matching, and remove matching ids if the frame being restored is deleted. Obey :delete. * lisp/desktop.el (desktop-restore-forces-onscreen) (desktop-restore-reuses-frames): Document :keyword constant values. (desktop-filter-parameters-alist): Remove, now identical to frameset-filter-alist. (desktop--filter-tty*): Remove, moved to frameset.el. (desktop-save-frameset, desktop-restore-frameset): Do not pass :filters argument.
-rw-r--r--lisp/ChangeLog26
-rw-r--r--lisp/desktop.el29
-rw-r--r--lisp/frameset.el289
3 files changed, 202 insertions, 142 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 66bf7422b0d..de1da73bbb1 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,29 @@
12013-08-04 Juanma Barranquero <lekktu@gmail.com>
2
3 * desktop.el (desktop-restore-forces-onscreen)
4 (desktop-restore-reuses-frames): Document :keyword constant values.
5 (desktop-filter-parameters-alist): Remove, now identical to
6 frameset-filter-alist.
7 (desktop--filter-tty*): Remove, moved to frameset.el.
8 (desktop-save-frameset, desktop-restore-frameset):
9 Do not pass :filters argument.
10
11 * frameset.el (frameset-live-filter-alist)
12 (frameset-persistent-filter-alist): New variables.
13 (frameset-filter-alist): Use them. Add autoload cookie.
14 (frameset-filter-tty-to-GUI): Move from desktop.el and rename.
15 (frameset--set-id, frameset--reuse-frame): Rename `frame-id' to
16 `frameset--id' (it's supposed to be internal to frameset.el).
17 (frameset--process-minibuffer-frames): Ditto. Doc fix.
18 (frameset--initial-params): New function.
19 (frameset--get-frame): Use it. Doc fix.
20 (frameset--move-onscreen): Accept new PRED value for FORCE-ONSCREEN.
21 Accept :all, not 'all.
22 (frameset-restore): Add new predicate values for FORCE-ONSCREEN and
23 FORCE-DISPLAY. Use :keywords for constant arguments to avoid collision
24 with fbound symbols. Fix frame id matching, and remove matching ids if
25 the frame being restored is deleted. Obey :delete.
26
12013-08-04 Stefan Monnier <monnier@iro.umontreal.ca> 272013-08-04 Stefan Monnier <monnier@iro.umontreal.ca>
2 28
3 * subr.el (macrop): New function. 29 * subr.el (macrop): New function.
diff --git a/lisp/desktop.el b/lisp/desktop.el
index 778c37484e1..ab78663c3d0 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -390,12 +390,12 @@ If `delete', frames on other displays are deleted instead of restored."
390 390
391(defcustom desktop-restore-forces-onscreen t 391(defcustom desktop-restore-forces-onscreen t
392 "If t, offscreen frames are restored onscreen instead. 392 "If t, offscreen frames are restored onscreen instead.
393If `all', frames that are partially offscreen are also forced onscren. 393If `:all', frames that are partially offscreen are also forced onscren.
394NOTE: Checking of frame boundaries is only approximate and can fail 394NOTE: Checking of frame boundaries is only approximate and can fail
395to reliably detect frames whose onscreen/offscreen state depends on a 395to reliably detect frames whose onscreen/offscreen state depends on a
396few pixels, especially near the right / bottom borders of the screen." 396few pixels, especially near the right / bottom borders of the screen."
397 :type '(choice (const :tag "Only fully offscreen frames" t) 397 :type '(choice (const :tag "Only fully offscreen frames" t)
398 (const :tag "Also partially offscreen frames" 'all) 398 (const :tag "Also partially offscreen frames" :all)
399 (const :tag "Do not force frames onscreen" nil)) 399 (const :tag "Do not force frames onscreen" nil))
400 :group 'desktop 400 :group 'desktop
401 :version "24.4") 401 :version "24.4")
@@ -403,10 +403,10 @@ few pixels, especially near the right / bottom borders of the screen."
403(defcustom desktop-restore-reuses-frames t 403(defcustom desktop-restore-reuses-frames t
404 "If t, restoring frames reuses existing frames. 404 "If t, restoring frames reuses existing frames.
405If nil, existing frames are deleted. 405If nil, existing frames are deleted.
406If `keep', existing frames are kept and not reused." 406If `:keep', existing frames are kept and not reused."
407 :type '(choice (const :tag "Reuse existing frames" t) 407 :type '(choice (const :tag "Reuse existing frames" t)
408 (const :tag "Delete existing frames" nil) 408 (const :tag "Delete existing frames" nil)
409 (const :tag "Keep existing frames" 'keep)) 409 (const :tag "Keep existing frames" :keep))
410 :group 'desktop 410 :group 'desktop
411 :version "24.4") 411 :version "24.4")
412 412
@@ -900,25 +900,6 @@ DIRNAME must be the directory in which the desktop file will be saved."
900 900
901 901
902;; ---------------------------------------------------------------------------- 902;; ----------------------------------------------------------------------------
903(defvar desktop-filter-parameters-alist
904 (append '((font-backend . t)
905 (name . t)
906 (outer-window-id . t)
907 (parent-id . t)
908 (tty . desktop--filter-tty*)
909 (tty-type . desktop--filter-tty*)
910 (window-id . t)
911 (window-system . t))
912 frameset-filter-alist)
913 "Alist of frame parameters and filtering functions.
914Its format is identical to `frameset-filter-alist' (which see).")
915
916(defun desktop--filter-tty* (_current parameters saving)
917 ;; Remove tty and tty-type parameters when switching
918 ;; to a GUI frame.
919 (or saving
920 (not (frameset-switch-to-gui-p parameters))))
921
922(defun desktop--check-dont-save (frame) 903(defun desktop--check-dont-save (frame)
923 (not (frame-parameter frame 'desktop-dont-save))) 904 (not (frame-parameter frame 'desktop-dont-save)))
924 905
@@ -932,7 +913,6 @@ Frames with a non-nil `desktop-dont-save' parameter are not saved."
932 (let ((name (concat user-login-name "@" system-name 913 (let ((name (concat user-login-name "@" system-name
933 (format-time-string " %Y-%m-%d %T")))) 914 (format-time-string " %Y-%m-%d %T"))))
934 (frameset-save nil 915 (frameset-save nil
935 :filters desktop-filter-parameters-alist
936 :predicate #'desktop--check-dont-save 916 :predicate #'desktop--check-dont-save
937 :properties (list :app desktop--app-id 917 :properties (list :app desktop--app-id
938 :name name)))))) 918 :name name))))))
@@ -1049,7 +1029,6 @@ This function depends on the value of `desktop-saved-frameset'
1049being set (usually, by reading it from the desktop)." 1029being set (usually, by reading it from the desktop)."
1050 (when (desktop-restoring-frameset-p) 1030 (when (desktop-restoring-frameset-p)
1051 (frameset-restore desktop-saved-frameset 1031 (frameset-restore desktop-saved-frameset
1052 :filters desktop-filter-parameters-alist
1053 :reuse-frames desktop-restore-reuses-frames 1032 :reuse-frames desktop-restore-reuses-frames
1054 :force-display desktop-restore-in-current-display 1033 :force-display desktop-restore-in-current-display
1055 :force-onscreen desktop-restore-forces-onscreen))) 1034 :force-onscreen desktop-restore-forces-onscreen)))
diff --git a/lisp/frameset.el b/lisp/frameset.el
index 2a6a0d2dfb8..b24e4ed9362 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -46,16 +46,16 @@
46;; user-defined serializable data. Currently defined properties 46;; user-defined serializable data. Currently defined properties
47;; include: 47;; include:
48;; :version ID - Identifies the version of the frameset struct; 48;; :version ID - Identifies the version of the frameset struct;
49;; this is the only property always present and 49;; this is the only property always present and
50;; must not be modified. 50;; must not be modified.
51;; :app APPINFO - Freeform. Can be used by applications and 51;; :app APPINFO - Freeform. Can be used by applications and
52;; packages to indicate the intended (but by no 52;; packages to indicate the intended (but by no
53;; means exclusive) use of the frameset. For 53;; means exclusive) use of the frameset. For
54;; example, currently desktop.el sets :app to 54;; example, currently desktop.el sets :app to
55;; `(desktop . ,desktop-file-version). 55;; `(desktop . ,desktop-file-version).
56;; :name NAME - The name of the frameset instance; a string. 56;; :name NAME - The name of the frameset instance; a string.
57;; :desc TEXT - A description for user consumption (to choose 57;; :desc TEXT - A description for user consumption (to choose
58;; among framesets, etc.); a string. 58;; among framesets, etc.); a string.
59;; - states: an alist of items (FRAME-PARAMETERS . WINDOW-STATE) in 59;; - states: an alist of items (FRAME-PARAMETERS . WINDOW-STATE) in
60;; no particular order. Each item represents a frame to be 60;; no particular order. Each item represents a frame to be
61;; restored. 61;; restored.
@@ -98,46 +98,66 @@ Properties other than :version can be set with
98 98
99;; Filtering 99;; Filtering
100 100
101(defvar frameset-filter-alist 101;;;###autoload
102 '((background-color . frameset-filter-sanitize-color) 102(defvar frameset-live-filter-alist
103 (buffer-list . t) 103 '((name . t)
104 (buffer-predicate . t) 104 (minibuffer . frameset-filter-minibuffer)
105 (buried-buffer-list . t) 105 (top . frameset-filter-iconified))
106 (font . frameset-filter-save-parm) 106 "Minimum set of parameters to filter for live (on-session) framesets.
107 (foreground-color . frameset-filter-sanitize-color) 107See `frameset-filter-alist' for a full description.")
108 (fullscreen . frameset-filter-save-parm) 108
109 (GUI:font . frameset-filter-restore-parm) 109;;;###autoload
110 (GUI:fullscreen . frameset-filter-restore-parm) 110(defvar frameset-persistent-filter-alist
111 (GUI:height . frameset-filter-restore-parm) 111 (nconc
112 (GUI:width . frameset-filter-restore-parm) 112 '((background-color . frameset-filter-sanitize-color)
113 (height . frameset-filter-save-parm) 113 (buffer-list . t)
114 (left . frameset-filter-iconified) 114 (buffer-predicate . t)
115 (minibuffer . frameset-filter-minibuffer) 115 (buried-buffer-list . t)
116 (top . frameset-filter-iconified) 116 (font . frameset-filter-save-parm)
117 (width . frameset-filter-save-parm)) 117 (foreground-color . frameset-filter-sanitize-color)
118 (fullscreen . frameset-filter-save-parm)
119 (GUI:font . frameset-filter-restore-parm)
120 (GUI:fullscreen . frameset-filter-restore-parm)
121 (GUI:height . frameset-filter-restore-parm)
122 (GUI:width . frameset-filter-restore-parm)
123 (height . frameset-filter-save-parm)
124 (left . frameset-filter-iconified)
125 (outer-window-id . t)
126 (parent-id . t)
127 (tty . frameset-filter-tty-to-GUI)
128 (tty-type . frameset-filter-tty-to-GUI)
129 (width . frameset-filter-save-parm)
130 (window-id . t)
131 (window-system . t))
132 frameset-live-filter-alist)
133 "Recommended set of parameters to filter for persistent framesets.
134See `frameset-filter-alist' for a full description.")
135
136;;;###autoload
137(defvar frameset-filter-alist frameset-persistent-filter-alist
118 "Alist of frame parameters and filtering functions. 138 "Alist of frame parameters and filtering functions.
119 139
120Each element is a cons (PARAM . ACTION), where PARAM is a parameter 140Each element is a cons (PARAM . ACTION), where PARAM is a parameter
121name (a symbol identifying a frame parameter), and ACTION can be: 141name (a symbol identifying a frame parameter), and ACTION can be:
122 142
123 t The parameter is always removed from the parameter list. 143 t The parameter is always removed from the parameter list.
124 :save The parameter is removed when saving the frame. 144 :save The parameter is removed when saving the frame.
125 :restore The parameter is removed when restoring the frame. 145 :restore The parameter is removed when restoring the frame.
126 FILTER A filter function. 146 FILTER A filter function.
127 147
128FILTER can be a symbol FILTER-FUN, or a list (FILTER-FUN ARGS...). 148FILTER can be a symbol FILTER-FUN, or a list (FILTER-FUN ARGS...).
129It will be called with four arguments CURRENT, FILTERED, PARAMETERS 149It will be called with four arguments CURRENT, FILTERED, PARAMETERS
130and SAVING, plus any additional ARGS: 150and SAVING, plus any additional ARGS:
131 151
132 CURRENT A cons (PARAM . VALUE), where PARAM is the one being 152 CURRENT A cons (PARAM . VALUE), where PARAM is the one being
133 filtered and VALUE is its current value. 153 filtered and VALUE is its current value.
134 FILTERED The alist of parameters filtered so far. 154 FILTERED The alist of parameters filtered so far.
135 PARAMETERS The complete alist of parameters being filtered, 155 PARAMETERS The complete alist of parameters being filtered,
136 SAVING Non-nil if filtering before saving state, nil otherwise. 156 SAVING Non-nil if filtering before saving state, nil otherwise.
137 157
138The FILTER-FUN function must return: 158The FILTER-FUN function must return:
139 nil CURRENT is removed from the list. 159 nil CURRENT is removed from the list.
140 t CURRENT is left as is. 160 t CURRENT is left as is.
141 (PARAM' . VALUE') Replace CURRENT with this. 161 (PARAM' . VALUE') Replace CURRENT with this.
142 162
143Frame parameters not on this list are passed intact.") 163Frame parameters not on this list are passed intact.")
@@ -156,9 +176,9 @@ Return t if PARAMETERS describes a text-only terminal and
156the target is a graphic display; otherwise return nil. 176the target is a graphic display; otherwise return nil.
157Only meaningful when called from a filtering function in 177Only meaningful when called from a filtering function in
158`frameset-filter-alist'." 178`frameset-filter-alist'."
159 (and frameset--target-display ; we're switching 179 (and frameset--target-display ; we're switching
160 (null (cdr (assq 'display parameters))) ; from a tty 180 (null (cdr (assq 'display parameters))) ; from a tty
161 (cdr frameset--target-display))) ; to a GUI display 181 (cdr frameset--target-display))) ; to a GUI display
162 182
163(defun frameset-switch-to-tty-p (parameters) 183(defun frameset-switch-to-tty-p (parameters)
164 "True when switching to a text-only terminal. 184 "True when switching to a text-only terminal.
@@ -167,9 +187,14 @@ the target is a text-only terminal; otherwise return nil.
167Only meaningful when called from a filtering function in 187Only meaningful when called from a filtering function in
168`frameset-filter-alist'." 188`frameset-filter-alist'."
169 (and frameset--target-display ; we're switching 189 (and frameset--target-display ; we're switching
170 (cdr (assq 'display parameters)) ; from a GUI display 190 (cdr (assq 'display parameters)) ; from a GUI display
171 (null (cdr frameset--target-display)))) ; to a tty 191 (null (cdr frameset--target-display)))) ; to a tty
172 192
193(defun frameset-filter-tty-to-GUI (_current _filtered parameters saving)
194 "Remove CURRENT when switching from tty to a graphic display."
195 (or saving
196 (not (frameset-switch-to-gui-p parameters))))
197
173(defun frameset-filter-sanitize-color (current _filtered parameters saving) 198(defun frameset-filter-sanitize-color (current _filtered parameters saving)
174 "When switching to a GUI frame, remove \"unspecified\" colors. 199 "When switching to a GUI frame, remove \"unspecified\" colors.
175Useful as a filter function for tty-specific parameters." 200Useful as a filter function for tty-specific parameters."
@@ -223,12 +248,6 @@ meaningless in an iconified frame, so the frame is restored in a
223default position." 248default position."
224 (not (and saving (eq (cdr (assq 'visibility parameters)) 'icon)))) 249 (not (and saving (eq (cdr (assq 'visibility parameters)) 'icon))))
225 250
226(defun frameset-keep-original-display-p (force-display)
227 "True if saved frames' displays should be honored."
228 (cond ((daemonp) t)
229 ((eq system-type 'windows-nt) nil)
230 (t (null force-display))))
231
232(defun frameset-filter-params (parameters filter-alist saving) 251(defun frameset-filter-params (parameters filter-alist saving)
233 "Filter parameter list PARAMETERS and return a filtered list. 252 "Filter parameter list PARAMETERS and return a filtered list.
234FILTER-ALIST is an alist of parameter filters, in the format of 253FILTER-ALIST is an alist of parameter filters, in the format of
@@ -265,18 +284,18 @@ nil while the filtering is done to restore it."
265;; Saving framesets 284;; Saving framesets
266 285
267(defun frameset--set-id (frame) 286(defun frameset--set-id (frame)
268 "Set FRAME's `frame-id' if not yet set. 287 "Set FRAME's `frameset--id' if not yet set.
269Internal use only." 288Internal use only."
270 (unless (frame-parameter frame 'frame-id) 289 (unless (frame-parameter frame 'frameset--id)
271 (set-frame-parameter frame 290 (set-frame-parameter frame
272 'frame-id 291 'frameset--id
273 (mapconcat (lambda (n) (format "%04X" n)) 292 (mapconcat (lambda (n) (format "%04X" n))
274 (cl-loop repeat 4 collect (random 65536)) 293 (cl-loop repeat 4 collect (random 65536))
275 "-")))) 294 "-"))))
276 295
277(defun frameset--process-minibuffer-frames (frame-list) 296(defun frameset--process-minibuffer-frames (frame-list)
278 "Process FRAME-LIST and record minibuffer relationships. 297 "Process FRAME-LIST and record minibuffer relationships.
279FRAME-LIST is a list of frames." 298FRAME-LIST is a list of frames. Internal use only."
280 ;; Record frames with their own minibuffer 299 ;; Record frames with their own minibuffer
281 (dolist (frame (minibuffer-frame-list)) 300 (dolist (frame (minibuffer-frame-list))
282 (when (memq frame frame-list) 301 (when (memq frame frame-list)
@@ -292,12 +311,12 @@ FRAME-LIST is a list of frames."
292 (unless (frame-parameter frame 'frameset--mini) 311 (unless (frame-parameter frame 'frameset--mini)
293 (frameset--set-id frame) 312 (frameset--set-id frame)
294 (let* ((mb-frame (window-frame (minibuffer-window frame))) 313 (let* ((mb-frame (window-frame (minibuffer-window frame)))
295 (id (and mb-frame (frame-parameter mb-frame 'frame-id)))) 314 (id (and mb-frame (frame-parameter mb-frame 'frameset--id))))
296 (if (null id) 315 (if (null id)
297 (error "Minibuffer frame %S for %S is excluded" mb-frame frame) 316 (error "Minibuffer frame %S for %S is excluded" mb-frame frame)
298 ;; For minibufferless frames, frameset--mini is a cons 317 ;; For minibufferless frames, frameset--mini is a cons
299 ;; (nil . FRAME-ID), where FRAME-ID is the frame-id of 318 ;; (nil . FRAME-ID), where FRAME-ID is the frameset--id
300 ;; the frame containing its minibuffer window. 319 ;; of the frame containing its minibuffer window.
301 (set-frame-parameter frame 320 (set-frame-parameter frame
302 'frameset--mini 321 'frameset--mini
303 (cons nil id))))))) 322 (cons nil id)))))))
@@ -345,26 +364,32 @@ When forced onscreen, frames wider than the monitor's workarea are converted
345to fullwidth, and frames taller than the workarea are converted to fullheight. 364to fullwidth, and frames taller than the workarea are converted to fullheight.
346NOTE: This only works for non-iconified frames. Internal use only." 365NOTE: This only works for non-iconified frames. Internal use only."
347 (pcase-let* ((`(,left ,top ,width ,height) (cl-cdadr (frame-monitor-attributes frame))) 366 (pcase-let* ((`(,left ,top ,width ,height) (cl-cdadr (frame-monitor-attributes frame)))
348 (right (+ left width -1)) 367 (right (+ left width -1))
349 (bottom (+ top height -1)) 368 (bottom (+ top height -1))
350 (fr-left (frameset--compute-pos (frame-parameter frame 'left) left right)) 369 (fr-left (frameset--compute-pos (frame-parameter frame 'left) left right))
351 (fr-top (frameset--compute-pos (frame-parameter frame 'top) top bottom)) 370 (fr-top (frameset--compute-pos (frame-parameter frame 'top) top bottom))
352 (ch-width (frame-char-width frame)) 371 (ch-width (frame-char-width frame))
353 (ch-height (frame-char-height frame)) 372 (ch-height (frame-char-height frame))
354 (fr-width (max (frame-pixel-width frame) (* ch-width (frame-width frame)))) 373 (fr-width (max (frame-pixel-width frame) (* ch-width (frame-width frame))))
355 (fr-height (max (frame-pixel-height frame) (* ch-height (frame-height frame)))) 374 (fr-height (max (frame-pixel-height frame) (* ch-height (frame-height frame))))
356 (fr-right (+ fr-left fr-width -1)) 375 (fr-right (+ fr-left fr-width -1))
357 (fr-bottom (+ fr-top fr-height -1))) 376 (fr-bottom (+ fr-top fr-height -1)))
358 (when (pcase force-onscreen 377 (when (pcase force-onscreen
378 ;; A predicate.
379 ((pred functionp)
380 (funcall force-onscreen
381 frame
382 (list fr-left fr-top fr-width fr-height)
383 (list left top width height)))
359 ;; Any corner is outside the screen. 384 ;; Any corner is outside the screen.
360 (`all (or (< fr-bottom top) (> fr-bottom bottom) 385 (:all (or (< fr-bottom top) (> fr-bottom bottom)
361 (< fr-left left) (> fr-left right) 386 (< fr-left left) (> fr-left right)
362 (< fr-right left) (> fr-right right) 387 (< fr-right left) (> fr-right right)
363 (< fr-top top) (> fr-top bottom))) 388 (< fr-top top) (> fr-top bottom)))
364 ;; Displaced to the left, right, above or below the screen. 389 ;; Displaced to the left, right, above or below the screen.
365 (`t (or (> fr-left right) 390 (`t (or (> fr-left right)
366 (< fr-right left) 391 (< fr-right left)
367 (> fr-top bottom) 392 (> fr-top bottom)
368 (< fr-bottom top))) 393 (< fr-bottom top)))
369 ;; Fully inside, no need to do anything. 394 ;; Fully inside, no need to do anything.
370 (_ nil)) 395 (_ nil))
@@ -430,8 +455,8 @@ is the parameter list of the frame being restored. Internal use only."
430 ;; M-x desktop-read). 455 ;; M-x desktop-read).
431 (setq frame (frameset--find-frame 456 (setq frame (frameset--find-frame
432 (lambda (f id) 457 (lambda (f id)
433 (string= (frame-parameter f 'frame-id) id)) 458 (string= (frame-parameter f 'frameset--id) id))
434 display (cdr (assq 'frame-id frame-cfg)))) 459 display (cdr (assq 'frameset--id frame-cfg))))
435 ;; If it has not been loaded, and it is not a minibuffer-only frame, 460 ;; If it has not been loaded, and it is not a minibuffer-only frame,
436 ;; let's look for an existing non-minibuffer-only frame to reuse. 461 ;; let's look for an existing non-minibuffer-only frame to reuse.
437 (unless (or frame (eq (cdr (assq 'minibuffer frame-cfg)) 'only)) 462 (unless (or frame (eq (cdr (assq 'minibuffer frame-cfg)) 'only))
@@ -447,11 +472,11 @@ is the parameter list of the frame being restored. Internal use only."
447 ;; and that they are linked to the right minibuffer frame. 472 ;; and that they are linked to the right minibuffer frame.
448 (setq frame (frameset--find-frame 473 (setq frame (frameset--find-frame
449 (lambda (f id mini-id) 474 (lambda (f id mini-id)
450 (and (string= (frame-parameter f 'frame-id) id) 475 (and (string= (frame-parameter f 'frameset--id) id)
451 (string= (frame-parameter (window-frame (minibuffer-window f)) 476 (string= (frame-parameter (window-frame (minibuffer-window f))
452 'frame-id) 477 'frameset--id)
453 mini-id))) 478 mini-id)))
454 display (cdr (assq 'frame-id frame-cfg)) (cdr mini)))) 479 display (cdr (assq 'frameset--id frame-cfg)) (cdr mini))))
455 (t 480 (t
456 ;; Default to just finding a frame in the same display. 481 ;; Default to just finding a frame in the same display.
457 (setq frame (frameset--find-frame nil display)))) 482 (setq frame (frameset--find-frame nil display))))
@@ -460,11 +485,21 @@ is the parameter list of the frame being restored. Internal use only."
460 (setq frameset--reuse-list (delq frame frameset--reuse-list))) 485 (setq frameset--reuse-list (delq frame frameset--reuse-list)))
461 frame)) 486 frame))
462 487
488(defun frameset--initial-params (frame-cfg)
489 "Return parameters from FRAME-CFG that should not be changed later.
490Setting position and size parameters as soon as possible helps reducing
491flickering; other parameters, like `minibuffer' and `border-width', must
492be set when creating the frame because they can not be changed later.
493Internal use only."
494 (cl-loop for param in '(left top with height border-width minibuffer)
495 collect (assq param frame-cfg)))
496
463(defun frameset--get-frame (frame-cfg window-cfg filters force-onscreen) 497(defun frameset--get-frame (frame-cfg window-cfg filters force-onscreen)
464 "Set up and return a frame according to its saved state. 498 "Set up and return a frame according to its saved state.
465That means either reusing an existing frame or creating one anew. 499That means either reusing an existing frame or creating one anew.
466FRAME-CFG is the frame's parameter list; WINDOW-CFG is its window state. 500FRAME-CFG is the frame's parameter list; WINDOW-CFG is its window state.
467For the meaning of FORCE-ONSCREEN, see `frameset-restore'." 501For the meaning of FORCE-ONSCREEN, see `frameset-restore'.
502Internal use only."
468 (let* ((fullscreen (cdr (assq 'fullscreen frame-cfg))) 503 (let* ((fullscreen (cdr (assq 'fullscreen frame-cfg)))
469 (lines (assq 'tool-bar-lines frame-cfg)) 504 (lines (assq 'tool-bar-lines frame-cfg))
470 (filtered-cfg (frameset-filter-params frame-cfg filters nil)) 505 (filtered-cfg (frameset-filter-params frame-cfg filters nil))
@@ -507,9 +542,7 @@ For the meaning of FORCE-ONSCREEN, see `frameset-restore'."
507 (frameset--reuse-frame display filtered-cfg)) 542 (frameset--reuse-frame display filtered-cfg))
508 (make-frame-on-display display 543 (make-frame-on-display display
509 (cons '(visibility) 544 (cons '(visibility)
510 (cl-loop 545 (frameset--initial-params filtered-cfg)))))
511 for param in '(left top width height minibuffer)
512 collect (assq param filtered-cfg))))))
513 (modify-frame-parameters frame 546 (modify-frame-parameters frame
514 (if (eq (frame-parameter frame 'fullscreen) fullscreen) 547 (if (eq (frame-parameter frame 'fullscreen) fullscreen)
515 ;; Workaround for bug#14949 548 ;; Workaround for bug#14949
@@ -541,6 +574,12 @@ It sorts minibuffer-owning frames before minibufferless ones."
541 ((eq hasmini1 nil) (string< id-def1 id-def2)) 574 ((eq hasmini1 nil) (string< id-def1 id-def2))
542 (t t)))) 575 (t t))))
543 576
577(defun frameset-keep-original-display-p (force-display)
578 "True if saved frames' displays should be honored."
579 (cond ((daemonp) t)
580 ((eq system-type 'windows-nt) nil)
581 (t (not force-display))))
582
544(defun frameset-sort-frames-for-deletion (frame1 _frame2) 583(defun frameset-sort-frames-for-deletion (frame1 _frame2)
545 "Predicate to sort live frames for deletion. 584 "Predicate to sort live frames for deletion.
546Minibufferless frames must go first to avoid errors when attempting 585Minibufferless frames must go first to avoid errors when attempting
@@ -548,42 +587,53 @@ to delete a frame whose minibuffer window is used by another frame."
548 (not (frame-parameter frame1 'minibuffer))) 587 (not (frame-parameter frame1 'minibuffer)))
549 588
550;;;###autoload 589;;;###autoload
551(cl-defun frameset-restore (frameset &key filters reuse-frames force-display force-onscreen) 590(cl-defun frameset-restore (frameset
591 &key filters reuse-frames force-display force-onscreen)
552 "Restore a FRAMESET into the current display(s). 592 "Restore a FRAMESET into the current display(s).
553 593
554FILTERS is an alist of parameter filters; defaults to `frameset-filter-alist'. 594FILTERS is an alist of parameter filters; defaults to `frameset-filter-alist'.
555 595
556REUSE-FRAMES describes how to reuse existing frames while restoring a frameset: 596REUSE-FRAMES describes how to reuse existing frames while restoring a frameset:
557 t Reuse any existing frame if possible; delete leftover frames. 597 t Reuse any existing frame if possible; delete leftover frames.
558 nil Restore frameset in new frames and delete existing frames. 598 nil Restore frameset in new frames and delete existing frames.
559 keep Restore frameset in new frames and keep the existing ones. 599 :keep Restore frameset in new frames and keep the existing ones.
560 LIST A list of frames to reuse; only these will be reused, if possible, 600 LIST A list of frames to reuse; only these will be reused, if possible,
561 and any leftover one will be deleted; other frames not on this 601 and any leftover one will be deleted; other frames not on this
562 list will be kept. 602 list will be kept.
563 603
564FORCE-DISPLAY can be: 604FORCE-DISPLAY can be:
565 t Frames will be restored in the current display. 605 t Frames will be restored in the current display.
566 nil Frames will be restored, if possible, in their original displays. 606 nil Frames will be restored, if possible, in their original displays.
567 delete Frames in other displays will be deleted instead of restored. 607 :delete Frames in other displays will be deleted instead of restored.
608 PRED A function which will be called with one argument, the parameter
609 list, and must return t, nil or `:delete', as above but affecting
610 only the frame that will be created from that parameter list.
568 611
569FORCE-ONSCREEN can be: 612FORCE-ONSCREEN can be:
570 all Force onscreen any frame fully or partially offscreen. 613 :all Force onscreen any frame fully or partially offscreen.
571 t Force onscreen only those frames that are fully offscreen. 614 t Force onscreen only those frames that are fully offscreen.
572 nil Do not force any frame back onscreen. 615 nil Do not force any frame back onscreen.
616 PRED A function which will be called with three arguments,
617 - the live frame just restored,
618 - a list (LEFT TOP WIDTH HEIGHT), describing the frame,
619 - a list (LEFT TOP WIDTH HEIGHT), describing the workarea,
620 and must return non-nil to force the frame onscreen, nil otherwise.
621
622Note the timing and scope of the operations described above: REUSE-FRAMES
623affects existing frames, FILTERS and FORCE-DISPLAY affect the frame being
624restored before that happens, and FORCE-ONSCREEN affects the frame once
625it has been restored.
573 626
574All keywords default to nil." 627All keywords default to nil."
575 628
576 (cl-assert (frameset-p frameset)) 629 (cl-assert (frameset-p frameset))
577 630
578 (let* ((delete-saved (eq force-display 'delete)) 631 (let (other-frames)
579 (forcing (not (frameset-keep-original-display-p force-display)))
580 (target (and forcing (cons 'display (frame-parameter nil 'display))))
581 other-frames)
582 632
583 ;; frameset--reuse-list is a list of frames potentially reusable. Later we 633 ;; frameset--reuse-list is a list of frames potentially reusable. Later we
584 ;; will decide which ones can be reused, and how to deal with any leftover. 634 ;; will decide which ones can be reused, and how to deal with any leftover.
585 (pcase reuse-frames 635 (pcase reuse-frames
586 ((or `nil `keep) 636 ((or `nil `:keep)
587 (setq frameset--reuse-list nil 637 (setq frameset--reuse-list nil
588 other-frames (frame-list))) 638 other-frames (frame-list)))
589 ((pred consp) 639 ((pred consp)
@@ -604,35 +654,40 @@ All keywords default to nil."
604 ((and d-mini `(,hasmini . ,mb-id)) 654 ((and d-mini `(,hasmini . ,mb-id))
605 (cdr (assq 'frameset--mini frame-cfg))) 655 (cdr (assq 'frameset--mini frame-cfg)))
606 (default (and (booleanp mb-id) mb-id)) 656 (default (and (booleanp mb-id) mb-id))
657 (force-display (if (functionp force-display)
658 (funcall force-display frame-cfg)
659 force-display))
607 (frame nil) (to-tty nil)) 660 (frame nil) (to-tty nil))
608 ;; Only set target if forcing displays and the target display is different. 661 ;; Only set target if forcing displays and the target display is different.
609 (if (or (not forcing) 662 (cond ((frameset-keep-original-display-p force-display)
610 (equal target (or (assq 'display frame-cfg) '(display . nil)))) 663 (setq frameset--target-display nil))
611 (setq frameset--target-display nil) 664 ((eq (frame-parameter nil 'display) (cdr (assq 'display frame-cfg)))
612 (setq frameset--target-display target 665 (setq frameset--target-display nil))
613 to-tty (null (cdr target)))) 666 (t
614 ;; If keeping non-reusable frames, and the frame-id of one of them 667 (setq frameset--target-display (cons 'display
615 ;; matches the frame-id of a frame being restored (because, for example, 668 (frame-parameter nil 'display))
616 ;; the frameset has already been read in the same session), remove the 669 to-tty (null (cdr frameset--target-display)))))
617 ;; frame-id from the non-reusable frame, which is not useful anymore.
618 (when (and other-frames
619 (or (eq reuse-frames 'keep) (consp reuse-frames)))
620 (let ((dup (cl-find (cdr (assq 'frameset-frame-id frame-cfg))
621 other-frames
622 :key (lambda (frame)
623 (frame-parameter frame 'frameset-frame-id))
624 :test #'string=)))
625 (when dup
626 (set-frame-parameter dup 'frameset-frame-id nil))))
627 ;; Time to restore frames and set up their minibuffers as they were. 670 ;; Time to restore frames and set up their minibuffers as they were.
628 ;; We only skip a frame (thus deleting it) if either: 671 ;; We only skip a frame (thus deleting it) if either:
629 ;; - we're switching displays, and the user chose the option to delete, or 672 ;; - we're switching displays, and the user chose the option to delete, or
630 ;; - we're switching to tty, and the frame to restore is minibuffer-only. 673 ;; - we're switching to tty, and the frame to restore is minibuffer-only.
631 (unless (and frameset--target-display 674 (unless (and frameset--target-display
632 (or delete-saved 675 (or (eq force-display :delete)
633 (and to-tty 676 (and to-tty
634 (eq (cdr (assq 'minibuffer frame-cfg)) 'only)))) 677 (eq (cdr (assq 'minibuffer frame-cfg)) 'only))))
635 678 ;; If keeping non-reusable frames, and the frameset--id of one of them
679 ;; matches the id of a frame being restored (because, for example, the
680 ;; frameset has already been read in the same session), remove the
681 ;; frameset--id from the non-reusable frame, which is not useful anymore.
682 (when (and other-frames
683 (or (eq reuse-frames :keep) (consp reuse-frames)))
684 (let ((dup (cl-find (cdr (assq 'frameset--id frame-cfg))
685 other-frames
686 :key (lambda (frame)
687 (frame-parameter frame 'frameset--id))
688 :test #'string=)))
689 (when dup
690 (set-frame-parameter dup 'frameset--id nil))))
636 ;; Restore minibuffers. Some of this stuff could be done in a filter 691 ;; Restore minibuffers. Some of this stuff could be done in a filter
637 ;; function, but it would be messy because restoring minibuffers affects 692 ;; function, but it would be messy because restoring minibuffers affects
638 ;; global state; it's best to do it here than add a bunch of global 693 ;; global state; it's best to do it here than add a bunch of global
@@ -647,7 +702,7 @@ All keywords default to nil."
647 (t ;; Frame depends on other frame's minibuffer window. 702 (t ;; Frame depends on other frame's minibuffer window.
648 (let* ((mb-frame (or (cl-find-if 703 (let* ((mb-frame (or (cl-find-if
649 (lambda (f) 704 (lambda (f)
650 (string= (frame-parameter f 'frame-id) 705 (string= (frame-parameter f 'frameset--id)
651 mb-id)) 706 mb-id))
652 (frame-list)) 707 (frame-list))
653 (error "Minibuffer frame %S not found" mb-id))) 708 (error "Minibuffer frame %S not found" mb-id)))
@@ -658,14 +713,14 @@ All keywords default to nil."
658 (error "Not a minibuffer window %s" mb-window)) 713 (error "Not a minibuffer window %s" mb-window))
659 (if mb-param 714 (if mb-param
660 (setcdr mb-param mb-window) 715 (setcdr mb-param mb-window)
661 (push (cons 'minibuffer mb-window) frame-cfg)))))) 716 (push (cons 'minibuffer mb-window) frame-cfg)))))
662 ;; OK, we're ready at last to create (or reuse) a frame and 717 ;; OK, we're ready at last to create (or reuse) a frame and
663 ;; restore the window config. 718 ;; restore the window config.
664 (setq frame (frameset--get-frame frame-cfg window-cfg 719 (setq frame (frameset--get-frame frame-cfg window-cfg
665 (or filters frameset-filter-alist) 720 (or filters frameset-filter-alist)
666 force-onscreen)) 721 force-onscreen))
667 ;; Set default-minibuffer if required. 722 ;; Set default-minibuffer if required.
668 (when default (setq default-minibuffer-frame frame))) 723 (when default (setq default-minibuffer-frame frame))))
669 (error 724 (error
670 (delay-warning 'frameset (error-message-string err) :error)))) 725 (delay-warning 'frameset (error-message-string err) :error))))
671 726
@@ -674,7 +729,7 @@ All keywords default to nil."
674 (sit-for 0 t) 729 (sit-for 0 t)
675 730
676 ;; Delete remaining frames, but do not fail if some resist being deleted. 731 ;; Delete remaining frames, but do not fail if some resist being deleted.
677 (unless (eq reuse-frames 'keep) 732 (unless (eq reuse-frames :keep)
678 (dolist (frame (sort (nconc (if (listp reuse-frames) nil other-frames) 733 (dolist (frame (sort (nconc (if (listp reuse-frames) nil other-frames)
679 frameset--reuse-list) 734 frameset--reuse-list)
680 #'frameset-sort-frames-for-deletion)) 735 #'frameset-sort-frames-for-deletion))