unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* desktop.el: Add frames and windows configuration save&restore
@ 2012-01-18 18:09 Jérémy Compostella
  2012-01-18 19:34 ` Drew Adams
  2012-01-18 21:20 ` Stefan Monnier
  0 siblings, 2 replies; 7+ messages in thread
From: Jérémy Compostella @ 2012-01-18 18:09 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1454 bytes --]

All,

The attached patch provides the desktop frame and windows configuration
save&restore feature : the desktop module saves all the frame and their
respective windows configuration. On the next Emacs session, after
having restored all the buffers, the desktop module will then restore
all the frame with their window configuration.

This patch probably fits the following TODO item:

 ** Make desktop.el save the "frame configuration" of Emacs (in some
    useful sense).

I have tried to make this feature as customizable as possible:
- This feature is disabled by default with the customizable
  `desktop-save-frames' in order to keep the current behavior for users
  whose could not want this.
- The `desktop-save-selected-frame-only' force the frame and window
  configuration of the current frame only.
- The saved frame parameters is customizable through
  `desktop-frame-parameters-to-save'.
- The saved window properties is customizable through
  `desktop-window-properties-to-save'.

First, I was trying to implement this feature in one of my own Emacs
module but talking with other Emacs users around me I figured out that,
first, this feature is probably expected, and second, it should be
provided by the desktop package.

I've tried to write the best code I could but it's my first "important"
patch to this project and I will be happy to take all your remark into
account ;)

Best regards,

Jérémy


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-desktop.el-Add-frames-and-windows-configuration-save.patch --]
[-- Type: text/x-diff, Size: 8567 bytes --]

From cd4bb24cc4d367af8c0972b1dddbefec04ab18d8 Mon Sep 17 00:00:00 2001
From: Jeremy Compostella <jeremy.compostella@gmail.com>
Date: Mon, 16 Jan 2012 18:07:37 +0100
Subject: [PATCH] desktop.el: Add frames and windows configuration save&restore

When desktop-save-frames is not nil (set to nil by default), the
desktop-save functionn saves all the frame and their window
configuration. All the frames will be automatically restored on the
next Emacs session. When desktop-save-selected-frame-only is not nil
only the current frame is saved and restored.

Signed-off-by: Jeremy Compostella <jeremy.compostella@gmail.com>
---
 lisp/desktop.el |  151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 149 insertions(+), 2 deletions(-)

diff --git a/lisp/desktop.el b/lisp/desktop.el
index 2f79cc0..f7be80f 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -32,6 +32,7 @@
 ;;		- the mark & mark-active
 ;;		- buffer-read-only
 ;;		- some local variables
+;;      - the frames and their associated window configuration
 
 ;; To use this, use customize to turn on desktop-save-mode or add the
 ;; following line somewhere in your .emacs file:
@@ -132,7 +133,7 @@
 
 ;;; Code:
 
-(defvar desktop-file-version "206"
+(defvar desktop-file-version "207"
   "Version number of desktop file format.
 Written into the desktop file and used at desktop read to provide
 backward compatibility.")
@@ -390,6 +391,52 @@ See `desktop-restore-eager'."
   :group 'desktop
   :version "22.1")
 
+(defcustom desktop-save-frames nil
+  "If non-nil, offer to save and restore frames."
+  :type 'boolean
+  :group 'desktop
+  :version "24.1")
+
+(defcustom desktop-save-selected-frame-only nil
+  "If non-nil and `desktop-save-frames' non-nil, only the
+current frame will be saved."
+  :type 'boolean
+  :group 'desktop
+  :version "24.1")
+
+(defcustom desktop-frame-parameters-to-save
+  '(name
+    top
+    left
+    width
+    height
+    modeline
+    fullscreen
+    minibuffer
+    horizontal-scroll-bars
+    font-parameter
+    font
+    font-backend)
+  "List of parameter to save for each frame."
+  :type '(repeat symbol)
+  :group 'desktop)
+
+(defcustom desktop-window-properties-to-save
+  '((set-window-start       . window-start)
+    (set-window-point       . window-point)
+    (set-window-dedicated-p . window-dedicated-p)
+    (set-window-margins     . (lambda (w) `(,(car (window-margins w))
+					    ,(cdr (window-margins w)))))
+    (set-window-hscroll     . window-hscroll)
+    (set-window-scroll-bars . (lambda (w) (let ((scroll (window-scroll-bars w)))
+					    (cons (car scroll) (cddr scroll)))))
+    (set-window-fringes     . window-fringes))
+  "Associative list of window properties to save. Each property
+is a cons cell of two functions \"restore\" and \"save\". The
+\"restore\" function takes a window object and the returned value
+of the \"save\" function. The \"save\" function takes a window object
+as argument.")
+
 ;;;###autoload
 (defvar desktop-save-buffer nil
   "When non-nil, save buffer status in desktop file.
@@ -854,6 +901,92 @@ DIRNAME must be the directory in which the desktop file will be saved."
     ((eq desktop-file-name-format 'local) (file-relative-name filename dirname))
     (t (expand-file-name filename))))
 
+;; ----------------------------------------------------------------------------
+;; Frame and window configuration
+(defun desktop-window-info (window current-window)
+  "Return a list containing the WINDOW buffer-name, the WINDOW egdes, a
+boolean to true when WINDOW is the CURRENT-WINDOW and the WINDOW
+properties list as described by `desktop-window-properties-to-save'."
+  (let ((get-prop (lambda (fun)
+		    (let ((prop (funcall fun window)))
+		      (if (consp prop) prop (list prop))))))
+    (with-current-buffer (window-buffer window)
+      (list (buffer-name)
+	    (window-edges window)
+	    (eq window current-window)
+	    (mapcar (lambda (x) (cons (car x) (funcall get-prop (cdr x))))
+		    desktop-window-properties-to-save)))))
+
+;; ----------------------------------------------------------------------------
+(defun desktop-window-tree (frame)
+  "Return the window tree of frame FRAME replacing the window
+objects by their save informations as returned by `desktop-window-info'"
+  (let* ((current-window (with-selected-frame frame (selected-window)))
+	 (inner '(lambda (wtree)
+		   (if (windowp wtree)
+		       (desktop-window-info wtree current-window)
+		     (setcdr (cdr wtree) (list (mapcar inner (cddr wtree))))
+		     wtree))))
+    (funcall inner (car (window-tree frame)))))
+
+;; ----------------------------------------------------------------------------
+(defun desktop-frame-parameters (frame)
+  "Return the FRAME parameters associative list according to
+`desktop-frame-parameters-to-save'."
+  (mapcar (lambda (param)
+	    (cons param (let ((value (frame-parameter frame param)))
+			  (if (windowp value) t value))))
+	  desktop-frame-parameters-to-save))
+
+;; ----------------------------------------------------------------------------
+(defun desktop-restore-window (window-info)
+  "Restore the selected window properties from
+WINDOW-INFO. WINDOW-INFO is a list as returned by
+`desktop-window-info'."
+  (let* ((buf (get-buffer (car window-info)))
+	 (window (selected-window))
+	 (current-window (when (nth 2 window-info) window)))
+    (when buf
+      (switch-to-buffer buf)
+      (dolist (elm (nth 3 window-info))
+	(apply (car elm) (cons window (cdr elm)))))
+    (other-window 1)
+    current-window))
+
+;; ----------------------------------------------------------------------------
+(defun desktop-restore-window-tree (window-tree)
+  "Restore the selected frame window tree from
+WINDOW-TREE. WINDOW-TREE is a window tree as returned by
+`desktop-window-tree'."
+  (let ((current-window nil))
+    (if (stringp (car window-tree))
+	(desktop-restore-window window-tree)
+      (let* ((direction (car window-tree))
+	     (subtree-list (car (cddr window-tree)))
+	     (last-window (car (last subtree-list))))
+	(dolist (subtree subtree-list)
+	  (unless (eq last-window subtree)
+	    (let* ((edges (nth 1 subtree))
+		   (size (if direction
+			     (- (nth 3 edges) (nth 1 edges))
+			   (- (nth 2 edges) (nth 0 edges)))))
+	      (split-window nil size (not direction))))
+	  (let ((window (desktop-restore-window-tree subtree)))
+	    (when window (setq current-window window))))
+	current-window))))
+
+;; ----------------------------------------------------------------------------
+(defun desktop-restore-frame (use-current-frame frame-params window-tree)
+  "Restore a frame. If USE-CURRENT-FRAME is true, it uses the
+selected frame otherwise it creates a new one. FRAME-PARAMS is a
+frame parameters associative list as returned by
+`desktop-frame-parameters' and WINDOW-TREE is a window tree as
+returned by `desktop-window-tree'."
+  (when use-current-frame
+    (modify-frame-parameters (selected-frame) frame-params))
+  (with-selected-frame (or (and use-current-frame (selected-frame))
+  			   (make-frame frame-params))
+    (select-window (desktop-restore-window-tree window-tree))))
 
 ;; ----------------------------------------------------------------------------
 ;;;###autoload
@@ -920,6 +1053,17 @@ See also `desktop-base-file-name'."
 		  (insert "\n  " (desktop-value-to-string e)))
 		(insert ")\n\n"))))
 
+	  (when (and desktop-save-frames (window-system))
+	    (insert "\n;; Frame and window configuration section:\n")
+	    (let ((frames-to-save (if desktop-save-selected-frame-only
+				      `(,(selected-frame))
+				    (frame-list))))
+	      (dolist (frame frames-to-save)
+		(insert (format "\n(desktop-restore-frame %s '%S '%S)\n"
+				(eq (selected-frame) frame)
+				(desktop-frame-parameters frame)
+				(desktop-window-tree frame))))))
+
 	  (setq default-directory desktop-dirname)
 	  (let ((coding-system-for-write 'emacs-mule))
 	    (write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage))
@@ -1008,7 +1152,10 @@ Using it may cause conflicts.  Use it anyway? " owner)))))
 	    ;; move them here.
 	    (mapc 'bury-buffer
 		  (nreverse (cdr (memq desktop-first-buffer (nreverse (buffer-list))))))
-	    (switch-to-buffer (car (buffer-list)))
+	    ;; If frames are saved/restored the current buffer is
+	    ;; already restored
+	    (unless desktop-save-frames
+	      (switch-to-buffer (car (buffer-list))))
 	    (run-hooks 'desktop-delay-hook)
 	    (setq desktop-delay-hook nil)
 	    (run-hooks 'desktop-after-read-hook)
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-01-19 14:10 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-18 18:09 desktop.el: Add frames and windows configuration save&restore Jérémy Compostella
2012-01-18 19:34 ` Drew Adams
2012-01-18 21:20 ` Stefan Monnier
2012-01-18 22:30   ` Lennart Borgman
2012-01-19 13:07     ` Jérémy Compostella
2012-01-19 13:18       ` Lennart Borgman
2012-01-19 14:10         ` Jérémy Compostella

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).