Files @ 454aa3e3d784
Branch filter:

Location: workgroups2/src/workgroups-restore.el

Sergey Pashinin
restoring speedbar-mode
;;; 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)
      (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)
  "Restore `selected-frame's position from WCONFIG."
  (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 (selected-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)
  "Resize and position a frame based on WCONFIG of current workgroup."
  (interactive)
  (let* ((params (wg-wconfig-parameters wconfig))
         fullscreen)
    (set-frame-parameter nil 'fullscreen (if (assoc 'fullscreen params)
                                             (cdr (assoc 'fullscreen params))
                                           nil))
    (when (and wg-restore-frame-position
               (not (frame-parameter nil 'fullscreen)))
      (wg-wconfig-restore-frame-position wconfig))
    ))

(defun wg-restore-frame-size-position (wconfig)
  "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 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))
    ))

;; FIXME: throw a specific error if the restoration was unsuccessful
(defun wg-restore-wconfig (wconfig)
  "Restore a workgroup configuration WCONFIG in `selected-frame'.

Runs each time you're switching workgroups."
  (let ((wg-record-incorrectly-restored-bufs t)
        (wg-incorrectly-restored-bufs nil)
        (params (wg-wconfig-parameters wconfig))
        fullscreen wtree)
    (wg-barf-on-active-minibuffer)
    (wg-restore-frame-size-position wconfig)
    (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
     (if (not (wg-morph-p)) wtree (wg-morph 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))

    (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