Files @ 3edbfb87fe7d
Branch filter:

Location: workgroups2/src/workgroups-restore.el - annotation

Sergey Pashinin
Save/restore frames (#11)

Probably works (for me) with usual file buffers
02ed61787ebd
088605c05794
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
088605c05794
088605c05794
088605c05794
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
643551b0cac0
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
443938b472d4
443938b472d4
088605c05794
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
295f3038db4d
295f3038db4d
295f3038db4d
295f3038db4d
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
443938b472d4
443938b472d4
031a33ecd5cb
031a33ecd5cb
031a33ecd5cb
031a33ecd5cb
3edbfb87fe7d
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
02ed61787ebd
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
02ed61787ebd
02ed61787ebd
3edbfb87fe7d
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
0cd9bea1f5fe
0cd9bea1f5fe
0cd9bea1f5fe
0cd9bea1f5fe
0cd9bea1f5fe
0cd9bea1f5fe
0cd9bea1f5fe
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
3edbfb87fe7d
02ed61787ebd
3edbfb87fe7d
3edbfb87fe7d
443938b472d4
02ed61787ebd
02ed61787ebd
02ed61787ebd
443938b472d4
443938b472d4
443938b472d4
02ed61787ebd
02ed61787ebd
02ed61787ebd
7fbe795cca5a
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
02ed61787ebd
3edbfb87fe7d
02ed61787ebd
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
443938b472d4
02ed61787ebd
02ed61787ebd
;;; workgroups-restore --- Functions to restore buffers and frames
;;; Commentary:
;;
;; TIPS
;;---------
;; Each Emacs frame ("window") can contain several workgroups.
;; WCONFIG is settings for each workgroup (buffers, parameters,...)
;;
;; So restoring WCONFIG using `wg-restore-wconfig' is restoring buffers
;; for current workgroup. Generally speaking each Workgroup can have
;; several WCONFIGs.
;;
;;; Code:

(require 'workgroups-variables)

(defun wg-restore-default-buffer ()
  "Switch to `wg-default-buffer'."
  (switch-to-buffer wg-default-buffer t))

(defun wg-restore-existing-buffer (buf)
  "Switch to and return BUF's referrent (some live buffer) if it exists."
  (wg-awhen (wg-find-buf-in-buffer-list buf (buffer-list))
    (switch-to-buffer it t)
    (wg-set-buffer-uid-or-error (wg-buf-uid buf))
    it))

(defun wg-restore-file-buffer (buf)
  "Restore BUF by finding its file.  Return the created buffer.
If BUF's file doesn't exist, call `wg-restore-default-buffer'"
  (wg-when-let ((file-name (wg-buf-file-name buf)))
    (when (or wg-restore-remote-buffers
              (not (file-remote-p file-name)))
      (cond ((file-exists-p file-name)
             (find-file file-name)
             (rename-buffer (wg-buf-name buf) t)
             (wg-set-buffer-uid-or-error (wg-buf-uid buf))
             (when wg-restore-mark
               (set-mark (wg-buf-mark buf))
               (deactivate-mark))
             (wg-deserialize-buffer-local-variables buf)
             (current-buffer))
            (t
             ;; try directory
             (if (not (file-remote-p file-name))
                 (if (file-directory-p (file-name-directory file-name))
                     (progn
                       (dired (file-name-directory file-name))
                       (current-buffer))
                   (progn
                     (message "Attempt to restore nonexistent file: %S" file-name)
                     nil))
               nil)
             )))))

(defun wg-restore-special-buffer (buf)
  "Restore a buffer BUF with DESERIALIZER-FN."
  (wg-when-let
      ((special-data (wg-buf-special-data buf))
       (buffer (save-window-excursion
                 (condition-case err
                     (funcall (car special-data) buf)
                   (error (message "Error deserializing %S: %S"
                                   (wg-buf-name buf) err)
                          nil)))))
    (switch-to-buffer buffer t)
    (wg-set-buffer-uid-or-error (wg-buf-uid buf))
    buffer))

(defun wg-restore-buffer (buf)
  "Restore BUF and return it."
  (let (wg-buffer-auto-association-on)
    (or (wg-restore-existing-buffer buf)
        (wg-restore-special-buffer buf)
        (wg-restore-file-buffer buf)
        (progn (wg-restore-default-buffer) nil))))

(defun wg-restore-window-positions (win &optional window)
  "Restore various positions in WINDOW from their values in WIN."
  (let ((window (or window (selected-window))))
    (wg-with-slots win
        ((win-point wg-win-point)
         (win-start wg-win-start)
         (win-hscroll wg-win-hscroll))
      (set-window-start window win-start t)
      (set-window-hscroll window win-hscroll)
      (set-window-point
       window
       (cond ((not wg-restore-point) win-start)
             ((eq win-point :max) (point-max))
             (t win-point)))
      (when (>= win-start (point-max)) (recenter)))))

(defun wg-restore-window (win)
  "Restore WIN in `selected-window'."
  (let ((selwin (selected-window))
        (buf (wg-find-buf-by-uid (wg-win-buf-uid win))))
    (if (not buf) (wg-restore-default-buffer)
      (when (wg-restore-buffer buf)
        (wg-restore-window-positions win selwin)
        (when wg-restore-window-dedicated-p
          (set-window-dedicated-p selwin (wg-win-dedicated win)))))))

(defun wg-reset-window-tree ()
  "Delete all but one window in `selected-frame', and reset
various parameters of that window in preparation for restoring
a wtree."
  (delete-other-windows)
  (set-window-dedicated-p nil nil))

(defun wg-restore-window-tree-helper (w)
  "Recursion helper for `wg-restore-window-tree'."
  (if (wg-wtree-p w)
      (cl-loop with dir = (wg-wtree-dir w)
               for (win . rest) on (wg-wtree-wlist w)
               do (when rest (split-window nil (wg-w-size win dir) (not dir)))
               do (wg-restore-window-tree-helper win))
    (wg-restore-window w)
    (when (wg-win-selected w)
      (setq wg-window-tree-selected-window (selected-window)))
    (when (wg-win-minibuffer-scroll w)
      (setq minibuffer-scroll-window (selected-window)))
    (other-window 1)))

(defun wg-restore-window-tree (wtree)
  "Restore WTREE in `selected-frame'."
  (let ((window-min-width wg-window-min-width)
        (window-min-height wg-window-min-height)
        (wg-window-tree-selected-window nil))
    (wg-reset-window-tree)
    (wg-restore-window-tree-helper wtree)
    (wg-awhen wg-window-tree-selected-window (select-window it))))

(defun wg-wconfig-restore-frame-position (wconfig &optional frame)
  "Use WCONFIG to restore FRAME's position.
If frame is nil then `selected-frame'."
  (wg-when-let ((left (wg-wconfig-left wconfig))
                (top (wg-wconfig-top wconfig)))
    ;; Check that arguments are integers
    ;; Problem: https://github.com/pashinin/workgroups2/issues/15
    (if (and (integerp left)
             (integerp top))
        (set-frame-position frame left top))))

(defun wg-wconfig-restore-scroll-bars (wconfig)
  "Restore `selected-frame's scroll-bar settings from WCONFIG."
  (set-frame-parameter
   nil 'vertical-scroll-bars (wg-wconfig-vertical-scroll-bars wconfig))
  (set-frame-parameter
   nil 'scroll-bar-width (wg-wconfig-scroll-bar-width wconfig)))

;;(defun wg-wconfig-restore-fullscreen (wconfig)
;;  "Restore `selected-frame's fullscreen settings from WCONFIG."
;;  (set-frame-parameter
;;   nil 'fullscreen (wg-wconfig-parameters wconfig))
;;  )

(defun wg-scale-wconfig-to-frame (wconfig)
  "Scale WCONFIG buffers to fit current frame size.
Return a scaled copy of WCONFIG."
  (interactive)
  (wg-scale-wconfigs-wtree wconfig
                           (frame-parameter nil 'width)
                           (frame-parameter nil 'height)))

(defun wg-frame-resize-and-position (wconfig &optional frame)
  "Apply WCONFIG's size and position to a FRAME."
  (interactive)
  (unless frame
    (setq frame (selected-frame)))
  (let* ((params (wg-wconfig-parameters wconfig))
         fullscreen)
    (set-frame-parameter frame 'fullscreen (if (assoc 'fullscreen params)
                                               (cdr (assoc 'fullscreen params))
                                             nil))
    (when (and wg-restore-frame-position
               (not (frame-parameter frame 'fullscreen)))
      (wg-wconfig-restore-frame-position wconfig frame))
    ))

(defun wg-restore-frame-size-position (wconfig &optional fs)
  "Smart-restore of frame size and position.

Depending on `wg-remember-frame-for-each-wg' frame parameters may
be restored for each workgroup.

If `wg-remember-frame-for-each-wg' is nil (by default) then
current frame parameters are saved/restored to/from first
workgroup. And frame parameters for all other workgroups are just
ignored.
"
  (interactive)
  (let* ((params (wg-wconfig-parameters wconfig))
         fullscreen)
    ;; Frame maximized / fullscreen / none
    (unless wg-remember-frame-for-each-wg
      (setq params (wg-wconfig-parameters (wg-workgroup-working-wconfig (wg-first-workgroup)))))
    (setq fullscreen (if (assoc 'fullscreen params)
                         (cdr (assoc 'fullscreen params))
                       nil))
    (when (and fs
               fullscreen
               (or wg-remember-frame-for-each-wg
                   (null (wg-current-workgroup t))))
      (set-frame-parameter nil 'fullscreen fullscreen)
      ;; I had bugs restoring maximized frame:
      ;; Frame could be maximized but buffers are not scaled to fit it.
      ;;
      ;; Maybe because of `set-frame-parameter' takes some time to finish and is async.
      ;; So I tried this and it helped
      (sleep-for 0 100))

    ;; Position
    (when (and wg-restore-frame-position
               wg-remember-frame-for-each-wg
               (not (frame-parameter nil 'fullscreen)))
      (wg-wconfig-restore-frame-position wconfig))
    ))

(defun wg-restore-frames ()
  "Try to recreate opened frames, take info from session's 'frame-list parameter."
  (interactive)
  (delete-other-frames)
  (when (wg-current-session t)
    (let ((fl (wg-session-parameter (wg-current-session t) 'frame-list nil))
          (frame (selected-frame)))
      (mapc (lambda (wconfig)
              (with-selected-frame (make-frame)
                ;;(wg-frame-resize-and-position wconfig)
                ;;(wg-restore-frame-size-position wconfig)
                ;;(wg-wconfig-restore-frame-position wconfig)
                (wg-restore-wconfig wconfig)
                )) fl)
      (select-frame-set-input-focus frame))))

;; FIXME: throw a specific error if the restoration was unsuccessful
(defun wg-restore-wconfig (wconfig &optional frame)
  "Restore a workgroup configuration WCONFIG in a FRAME.
Runs each time you're switching workgroups."
  (unless frame
    (setq frame (selected-frame)))
  (let ((wg-record-incorrectly-restored-bufs t)
        (wg-incorrectly-restored-bufs nil)
        (params (wg-wconfig-parameters wconfig))
        fullscreen wtree)
    (wg-barf-on-active-minibuffer)
    (when wg-restore-scroll-bars
      (wg-wconfig-restore-scroll-bars wconfig))
    (setq wtree (wg-scale-wconfig-to-frame wconfig))  ; scale wtree to frame size

    ;; Restore buffers
    (wg-restore-window-tree wtree)

    ;; Restore frame position
    (when (and wg-restore-frame-position
               (not (frame-parameter nil 'fullscreen))
               (null (wg-current-workgroup t)))
      (wg-wconfig-restore-frame-position wconfig frame))

    (when wg-incorrectly-restored-bufs
      (message "Unable to restore these buffers: %S\
If you want, restore them manually and try again."
               (mapcar 'wg-buf-name wg-incorrectly-restored-bufs)))))



(provide 'workgroups-restore)
;;; workgroups-restore.el ends here