From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: =?utf-8?Q?J=C3=A9r=C3=A9my_Compostella?= Newsgroups: gmane.emacs.devel Subject: desktop.el: Add frames and windows configuration save&restore Date: Wed, 18 Jan 2012 19:09:44 +0100 Message-ID: <8762g8vq53.fsf@Apollo.jerryland.fr> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: dough.gmane.org 1326910181 28325 80.91.229.12 (18 Jan 2012 18:09:41 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Wed, 18 Jan 2012 18:09:41 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Jan 18 19:09:37 2012 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1RnZx2-0002zG-TS for ged-emacs-devel@m.gmane.org; Wed, 18 Jan 2012 19:09:37 +0100 Original-Received: from localhost ([::1]:42240 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RnZx2-0005HK-Az for ged-emacs-devel@m.gmane.org; Wed, 18 Jan 2012 13:09:36 -0500 Original-Received: from eggs.gnu.org ([140.186.70.92]:50852) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RnZwy-0005Ee-Ob for emacs-devel@gnu.org; Wed, 18 Jan 2012 13:09:34 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RnZww-00066F-NX for emacs-devel@gnu.org; Wed, 18 Jan 2012 13:09:32 -0500 Original-Received: from mail-we0-f169.google.com ([74.125.82.169]:34813) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RnZww-000669-G3 for emacs-devel@gnu.org; Wed, 18 Jan 2012 13:09:30 -0500 Original-Received: by werl4 with SMTP id l4so3292151wer.0 for ; Wed, 18 Jan 2012 10:09:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:subject:date:message-id:mime-version:content-type; bh=xQfgjWSGeoQceAaghXBHSo046rbJsZIsRV8Sx47/BLg=; b=w+3k0Xmx6MBNV42v+lEYpJi+/Q++ZqHiR0M7DhOlAKyeoXXToMhZb9QQfPkinPap4l fVw0gr9wc3s2HGpbzsiOY5211NrePFxxJlMD0Gw62/If5KKjnejuxqaZwA5T648BkSj/ f64XFWuKRkCsuR4kmly1+QRrd9+mZVOZ7Rad0= Original-Received: by 10.216.138.73 with SMTP id z51mr9530019wei.55.1326910169430; Wed, 18 Jan 2012 10:09:29 -0800 (PST) Original-Received: from Apollo.jerryland.fr (pierre.csie.fr. [212.51.164.178]) by mx.google.com with ESMTPS id q7sm23847684wix.5.2012.01.18.10.09.28 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 18 Jan 2012 10:09:28 -0800 (PST) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 74.125.82.169 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:147712 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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=C3=A9r=C3=A9my --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-desktop.el-Add-frames-and-windows-configuration-save.patch Content-Description: 0001-desktop.el-Add-frames-and-windows-configuration-save.patch >From cd4bb24cc4d367af8c0972b1dddbefec04ab18d8 Mon Sep 17 00:00:00 2001 From: Jeremy Compostella 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 --- 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 --=-=-=--