;;; windows.el --- Window manager for GNU Emacs. -*- coding: euc-jp -*- ;;; $Id: windows.el,v 2.56 2023/05/07 06:13:25 yuuji Exp $ ;;; (c) 1993-2020 by HIROSE Yuuji [yuuji>at win:max-configs 27) (error "win:max-configs too large!")) (defvar win:switch-prefix "\C-c\C-w" "*Prefix key stroke to switch windows") (defvar win:menu-key-stroke "\C-w" "*Key assignment of win-menu") (defvar win:resume-key-stroke "\C-r" "*Key assignment of win-resume-menu") (defvar win:resume-local-key-stroke "\C-l" "*Key assignment of win-resume-local-menu") (defvar win:switch-task-key-stroke "\C-s" "*Key assignment of win-switch-task") (defvar win:quick-selection t "*Non-nil enables a short cut for window selection; Not only with `C-c C-w 1' but also with `C-c 1'.") (defvar win:mode-line-format "[%c%s%s]" "*Format of mode line that shows the selected window number") ;;Variables for resume (defvar win:configuration-file (if (eq system-type 'ms-dos) "~/_windows" "~/.windows") "*File to save window configurations") (defvar win:local-config-file win:configuration-file "*Default local configuration file") (defvar win:make-backup-files t "*Create a backup of window configuration file or not") (defvar win:config-loaded nil "Flag if some configuration file is loaded or not") ;;Variables for Emacs 19 (defvar win:no-raise-at-save nil "*Non-nil inhibits win-save-all-configurations from raising each frame.") ;(Rev.1.4) (defvar win:frame-parameters-to-save-default (delq nil (list 'top 'left 'minibuffer 'vertical-scroll-bars (if (string< "19.27" emacs-version) 'menu-bar-lines) (if (featurep 'mule) 'line-space) ;; These parameters below should go to ;; win:frame-parameters-to-save-private ;; 'cursor-type 'auto-lower 'auto-raise 'cursor-color 'mouse-color ;; 'background-color 'foreground-color 'font )) "Which frame parameters to save; Do not modify this variable.") (defvar win:frame-parameters-to-save-private nil "*User defined list of frame parameters to save; You don't have to include neither 'heght nor 'width in this list because they are automatically saved in other method.") (defvar win:auto-position 'absolute "*Non-nil automatically positions the newly created frame; There are two methods of auto positioning, 'absolute for this variable puts the new frame by calculating its absolute coordinates. 'relative for this variable puts the new frame relative to currently selected frame.") (defvar win:new-frame-offset-x 50 "*X-Offset of new frame to currently selected frame; See win:auto-position.") (defvar win:new-frame-offset-y 10 "*Y-Offset of new frame to currently selected frame; See win:auto-position.") (defvar win:allocate-frame-hook nil "*Hook running at allocating new frame") (defvar win:resumed-frame-offset-x 0 "*X-Offset of resumed frame to compensate the window manager's border") (defvar win:resumed-frame-offset-y 0 "*Y-Offset of resumed frame to compensate the window manager's border") (defvar win:mouse-position '(0 -5) "*Mouse position list (X Y) in *pixel* at window selection") (defvar win:title-with-buffer-name t "*T means naming frame title with buffer name") (defvar win:wipe-also-frames nil "*T means wipe all frames but one when wipe-windows.") (defvar win:need-uptodate-frame-title t "*Set this to nil to disable frequent rewriting of frame title.") (defvar win:buffer-depth-per-win 5 "*Default depth of buffer stack per window. If nil, do not preserve buffer-list priority") (defvar win:names-maxl 20 "*Title length in window list") (defvar win:inhibit-switch-in-minibuffer nil "*Non-nil inhibits window switching in minibuffer window") ;;Variables for XEmacs (defvar win:frame-title-function (function(lambda (index) (format (if (featurep 'mule) "mule[%d]" "emacs[%d]") index))) "*Window title creation function. One argument of frame number should be taken.") ;;; ---------- Internal work variables (defvar win:configs (make-vector win:max-configs nil) "Array of window configurations; 0th always has previous configuration.") (defvar win:names (make-vector win:max-configs "")) (defvar win:names-prefix (make-vector win:max-configs "")) (defvar win:sizes (make-vector win:max-configs nil)) (defvar win:buflists (make-vector win:max-configs nil)) (let ((i 0)) (while (< i win:max-configs) (aset win:buflists i (make-vector win:buffer-depth-per-win nil)) (setq i (1+ i)))) (defvar win:current-config 0 "Current window buffer number") (defvar win:last-config 0 "Buffer number for a window previously seen") (defvar win:switch-map nil "Key map for window switcher") (defvar win:switch-menu-map nil "Keymap used in window selection menu") ;; for XEmacs (defvar win:xemacs-p (string-match "XEmacs" emacs-version)) (defvar win:XEmacs-remake-initial-frame win:xemacs-p "*Non-nil delets initial frame and rebuild same frame with name mule[1]") (defun win:remake-frame () (if win:XEmacs-remake-initial-frame (let ((old (selected-frame))) (prog1 (make-frame (cons (cons 'name "mule[1]") (mapcar (function(lambda (s) (cons s (frame-property old s))) '(top left height width))))) (delete-frame old))))) (defun win:sit-for-a-while (&optional secstr) "Wrap function to cover floating point number with string" (let ((defsec (if (and window-system (eq window-system 'w32)) "0.2" "0.1"))) (sit-for (string-to-number (or secstr defsec))))) (defun win:make-frame (index &optional prop) "Wrapper function for make-frame; INDEX is a window number. Optional second argument PROP is passed to make-frame function." (if win:frame-title-function (setq prop (cons (cons 'name (funcall win:frame-title-function index)) prop))) (if win:xemacs-p (make-frame (alist-to-plist prop)) (let ((frame (make-frame prop)) (count 100)) ;;(modify-frame-parameters frame prop) (if (string-match "^2[01]\\." emacs-version) (progn (while (and (> count 0) (not (frame-visible-p frame))) (setq count (1- count)) (win:sit-for-a-while)) ;;Emacs 20 becomes not to support top/left for initial parameter. (modify-frame-parameters frame prop))) frame))) ;; for Emacs-19 (defvar win:use-frame (and (string< "18" (substring emacs-version 0 2)) window-system) "*Non-nil means switch windows with frame.") (and (fboundp 'eval-when-compile) (eval-when-compile (require 'revive))) ;; for Emacs-24.3+ (defun win:last-key () "Return last-command-event or last-command-char." (if (boundp 'last-command-char) last-command-char last-command-event)) (if win:switch-map nil (setq win:switch-map (make-sparse-keymap) win:switch-menu-map (make-keymap)) (suppress-keymap win:switch-menu-map) (define-key global-map win:switch-prefix nil) (define-key global-map win:switch-prefix win:switch-map) (let ((key win:base-key) (max (+ win:base-key win:max-configs))) (while (< key max) (define-key win:switch-map (char-to-string key) 'win-switch-to-window) (setq key (1+ key))) ;`key' increasing (if (and win:quick-selection (> (length win:switch-prefix) 1)) (let ((prefix (substring win:switch-prefix 0 1))) (while (>= key win:base-key) (setq key (1- key)) (define-key global-map (concat prefix (char-to-string key)) 'win-switch-to-window)) (define-key global-map (concat prefix "=") 'win-switch-menu) (define-key global-map (concat prefix " ") 'win-toggle-window) (define-key global-map (concat prefix "!") 'win-delete-current-window) (define-key global-map (concat prefix "-") 'win-recover-recent-winconf))) (setq key win:base-key) (while (< key max) (define-key win:switch-menu-map (char-to-string key) 'win-switch-menu-select-directly) (setq key (1+ key)))) (define-key win:switch-map "=" 'win-switch-menu) (define-key win:switch-map win:menu-key-stroke 'win-menu) (define-key win:switch-map win:resume-key-stroke 'win-resume-menu) (define-key win:switch-map win:resume-local-key-stroke 'win-resume-local) (define-key win:switch-map win:switch-task-key-stroke 'win-switch-task) (define-key win:switch-map " " 'win-toggle-window) (define-key win:switch-map "\C-n" 'win-next-window) (define-key win:switch-map "n" 'win-next-window) (define-key win:switch-map "\C-p" 'win-prev-window) (define-key win:switch-map "p" 'win-prev-window) (define-key win:switch-map "-" 'win-recover-recent-winconf) (define-key win:switch-map "!" 'win-delete-current-window) ;; Key map of window selection menu. (define-key win:switch-menu-map "n" 'next-line) (define-key win:switch-menu-map "p" 'previous-line) (define-key win:switch-menu-map "\C-m" 'win-switch-menu-select) (define-key win:switch-menu-map " " 'win-switch-menu-select) (define-key win:switch-menu-map "f" 'win-switch-menu-select) (define-key win:switch-menu-map "s" 'win-switch-menu-mark-job) (define-key win:switch-menu-map "l" 'win-switch-menu-mark-job) (define-key win:switch-menu-map "d" 'win-switch-menu-mark-job) (define-key win:switch-menu-map "k" 'win-switch-menu-mark-job) (define-key win:switch-menu-map "u" 'win-switch-menu-unmark-job) (define-key win:switch-menu-map "e" 'win-switch-menu-edit-name-prefix) (define-key win:switch-menu-map "x" 'win-switch-menu-execute-job) (define-key win:switch-menu-map "q" 'win-switch-menu-quit) (define-key win:switch-menu-map "?" 'describe-mode) ;;Next lines prevent accidents (mapcar (function (lambda (func) (mapcar (function (lambda (key) (define-key win:switch-menu-map key ""))) (where-is-internal func)))) '(switch-to-buffer other-window other-frame kill-buffer save-buffer)) (define-key win:switch-menu-map win:switch-prefix "") (define-key win:switch-menu-map (substring win:switch-prefix 0 1) "") (run-hooks 'windows-keymap-setup-hook) ) ;; define menu-bar (if (or (null (fboundp 'make-frame)) (or (not (boundp 'window-system)) (not window-system))) nil ;Emacs 18 or emacs -nw (cond (win:xemacs-p (defvar win:xemacs-resume-menu '("Resume menu" ["Save all" (win-resume-menu nil ?a) t] ["Resume" (win-resume-menu nil ?r) t] ["Save this window" (win-resume-menu nil ?s) t] ["Load this window" (win-resume-menu nil ?l) t] ["Load from backup file" (win-resume-menu nil ?~) t] ["Wipe" (win-resume-menu nil ?w) t])) (defvar win:xemacs-top-menu '("Windows" ; :filter windows-menu-filter ["Next window frame" win-next-window t] ["Preious window frame" win-prev-window t] ["Switch task" win-switch-task t] ["local" win-resume-local t] ["--" nil nil] ["See you! (Revivable)" see-you-again t] ["Revive!" resume-windows t])) (add-submenu nil win:xemacs-top-menu "Edit") (add-submenu '("Windows") win:xemacs-resume-menu) (set-menubar current-menubar) (set-menubar-dirty-flag) ) (t ;GNU Emacs-19 or later (defvar win:menu-bar-buffer-map (make-sparse-keymap "Windows")) (defvar win:menu-bar-file-map (make-sparse-keymap "Windows resume menu")) (fset 'win:update-menu-bar (function (lambda () (define-key-after (lookup-key global-map [menu-bar buffer]) [windows] (cons "Windows" win:menu-bar-buffer-map) [frames])))) (define-key win:menu-bar-buffer-map [resume] (cons "Resume menu" (make-sparse-keymap "Resume menu"))) (mapcar (function (lambda (bind) (define-key win:menu-bar-buffer-map (vector 'resume (car bind)) (cons (nth 1 bind) (list 'lambda nil '(interactive) (list 'win-resume-menu nil (nth 2 bind))))))) (nreverse '((save-all "Save all" ?a) (resume "Resume" ?r) (save "Save this window" ?s) (load "Load this window" ?l) (back "Load from backup file" ?~) (wipe "Wipe" ?w)))) (mapcar (function (lambda (bind) (define-key win:menu-bar-buffer-map (vector (car bind)) (cdr bind)))) (nreverse '((next "Next window frame" . win-next-window) (prev "Previous window frame" . win-prev-window) (delete "Delete current window frame" . win-delete-current-window) ;;(load "Load all configuration" . win-load-all-configurations) ;;(save "Save all configuration" . win-save-all-configurations) (switch "Switch task" . win-switch-task) ;(resume "Resume menu" . win-resume-menu) (local "Local resume" . win-resume-local) ))) (define-key-after (or (lookup-key global-map [menu-bar file]) (lookup-key global-map [menu-bar files])) [see-you] (cons "See you!(revivable)" 'see-you-again) 'kill-buffer) (define-key-after (or (lookup-key global-map [menu-bar file]) (lookup-key global-map [menu-bar files])) [revive] (cons "Revive!" 'resume-windows) 'see-you) (add-hook 'menu-bar-update-hook 'win:update-menu-bar t)))) (defun win:No-of-windows () (let ((i 1) (num 0)) (while (< i win:max-configs) (if (aref win:configs i) (setq num (1+ num))) (setq i (1+ i))) num)) (defun win:free-window-min () "Search a window which is not displayed currently nor previously." (let ((i 1) num) (catch 'free (while (< i win:max-configs) (if (and (aref win:configs i) (/= i win:current-config) (/= i win:last-config)) (throw 'free i)) (setq i (1+ i))) (throw 'free win:last-config)))) (defun win:delete-window (n &optional killbufmsg force) "Delete Nth entry of window configuration buffer." (if (= n 0) (error "Can't delete window %c" win:base-key)) (if (and (<= (win:No-of-windows) 1) ;;if there's 1 window and it is (aref win:configs n)) ;;currently selected window (error "Can't delete sole window")) (if (or force (y-or-n-p (format "Erase %sconfiguration of %c{%s}?" (if killbufmsg "buffer and " "") (+ n win:base-key) (aref win:names n)))) (progn (cond (win:use-frame (delete-frame (aref win:configs n))) ;; no use-frame ((and (fboundp 'delete-frame) (null window-system) (string< "20" emacs-version)) (save-window-excursion (win:set-window-configuration (aref win:configs n)) (delete-frame (selected-frame))))) (aset win:configs n nil) (aset win:names-prefix n "") (if (= n win:current-config) (let ((free (win:free-window-min))) (setq win:current-config win:last-config win:last-config free) (win:set-wc win:current-config))) (win:update-mode-line win:current-config))) (message "")) (defun win:store-buffer-list (index) "(Windows internal)Store current window's buffer-list top 5" (let ((d 0) (bl (buffer-list))) (while (and (< d win:buffer-depth-per-win) bl) (or (eq (window-buffer (minibuffer-window)) (car bl)) ;(string-match "\\*$" (buffer-name (car bl))) (progn ;buffer-listの順序保存 (aset (aref win:buflists index) d (buffer-name (car bl))) (setq d (1+ d)))) (setq bl (cdr bl))))) (defun win:restore-buffer-list (index) "(Windows internal)Restore current window's buffer-list previously saved." (save-window-excursion (if (eq (selected-window) (minibuffer-window)) ;;escape from minibuffer (let ((wl (revive:window-list))) (while wl (select-window (car wl)) (if (eq (selected-window) (minibuffer-window)) (setq wl (cdr wl)) (setq wl nil))))) (let ((d win:buffer-depth-per-win) b) ;(select-window (get-largest-window)) (delete-other-windows) (while (> d 0) (setq d (1- d) b (aref (aref win:buflists index) d)) (and b (get-buffer b) (switch-to-buffer b)))))) (defun win:switch-window (to &optional preserve nosetwc) "(windows internal) Switch to window TO, changing win:{last,current}-config. Optional second arg PRESERVE non-nil inhibits updation of win:current-config. Optional third arg NOSETWC non-nil means do not set-window-configuration TO. " (win:adjust-window t) (if win:buffer-depth-per-win (win:store-buffer-list win:current-config)) (cond (win:use-frame (or preserve (if (win:frame-window (selected-frame)) (win:store-config win:current-config))) (if (aref win:configs to) nil (aset win:configs to (if (win:selected-window) (win:allocate-frame to) (selected-frame)))) (if (win:select-frame to) ;if succeeded (if win:buffer-depth-per-win (win:restore-buffer-list to)) (aset win:configs to nil) ;failed (error "Window frame [%c] does not exist." (+ win:base-key to)))) (t ;NOT use-frame (or preserve (win:store-config win:current-config)) (or nosetwc (win:set-wc to)) (if win:buffer-depth-per-win (save-window-excursion (win:restore-buffer-list to))) (and win:frames-in-nw (null (aref win:configs to)) (select-frame (make-frame (list (cons 'name (format "W:%d" to)))))))) (win:update-mode-line to) (if (/= to win:current-config) (setq win:last-config win:current-config win:current-config to)) (win:memorize-current-conf-1) (message "Switch to window[%c]" (+ to win:base-key))) (defun win-delete-current-window (arg) "Delete selected window configuration buffer. Non-nil for ARG kills all visible buffer." (interactive "P") (if win:use-frame (win:adjust-window t) (win:set-window-name win:current-config)) ;set window name (let ((cwin (selected-window)) win (cc win:current-config) (blist (list (current-buffer)))) (if arg (progn (setq win cwin) (while (not (eq cwin (setq win (next-window win)))) (setq blist (cons (window-buffer win) blist))))) (win:adjust-window) (win:store-config win:current-config) (win:delete-window win:current-config arg) (if (and arg (/= cc win:current-config)) (progn (while blist (if (get-buffer (car blist)) (kill-buffer (car blist))) (setq blist (cdr blist))))))) (defun win:kill-buffer-with-window () "Kill current window if it was created by KeyFunc&Exit." (and win:kill-buffer-with (equal win:current-config win:kill-buffer-with) (win:delete-window win:current-config nil t))) (defvar win:kill-buffer-with nil "If win:current-config is equal to this, delete this window.") (make-variable-buffer-local 'win:kill-buffer-with) ;;;###autoload (defun win-switch-to-window (arg &optional window) "Switch window configurations to a buffer specified by keyboard. If calling from program, optional second argument WINDOW can specify the window number." (interactive "p") (let*((lc (win:last-key)) (window (or window (if (and (> ?\M-0 0) (<= ?\M-0 lc)) (- lc ?\M-0) (- lc win:base-key)))) (wc (aref win:configs window))) (cond ((and win:inhibit-switch-in-minibuffer (eq (minibuffer-window) (selected-window))) (message "Really? Then, set win:inhibit-switch-in-minibuffer to nil!") (sit-for 1)) ;;if ARG=0, switch to recent window. ((= window 0) (win-recent-window)) ;;if ARG<0, delete specified(by invoke key) window. ((< arg 0) (win:delete-window window)) ;;if ARG>0, update specified(by invoke key) window. ((> arg 1) (win:switch-window window t t) (message "Update window[%c]" (+ window win:base-key))) ;;if specified window is current window. ((= win:current-config window) (if (= arg 0) (win:set-wc window) (if win:use-frame (win:switch-window window) (message "This is window[%c]." (+ window win:base-key))))) ;;else... ;;switch to specified window. (t (if (aref win:configs window) ;;if target window already exists. (win:switch-window window) ;;if target window does not exist. (let (ans) (if (= (+ win:current-config win:last-config) 0) (message "Create window[%c]?(y or n):" (+ window win:base-key)) (message (concat "[%c] is nil. C)reate D)up " (if win:use-frame "" "P)reserve ") "F)indfile B)uff X)M-x k)KeyFunc&exit N)o:") (+ window win:base-key))) ;;(setq ans (if (interactive-p) (read-char) ?y)) (setq ans (read-char)) (if (string-match (char-to-string ans) "cdpyfbxk") (let (inhibitmsg) (cond ((equal ans ?f) (let ((file (read-file-name "Find file on new window: "))) (win:switch-window window nil t) (delete-other-windows) (switch-to-buffer (get-buffer-create "*scratch*")) (sit-for 0) (find-file file))) ((equal ans ?b) (let ((buf (read-buffer "Switch to buffer on new window: " (other-buffer)))) (win:switch-window window nil t) (delete-other-windows) (switch-to-buffer buf))) ((equal ans ?x) (let ((cmd (read-command "M-x on new window: "))) (win:switch-window window nil t) (delete-other-windows) (switch-to-buffer (get-buffer-create "*scratch*")) (sit-for 0) (setq inhibitmsg t) (call-interactively cmd))) ((equal ans ?k) (let ((cmd (key-binding (read-key-sequence "Keysequence function on new window(deleted in the future): ")))) (win:switch-window window nil t) (delete-other-windows) (switch-to-buffer (get-buffer-create "*scratch*")) (sit-for 0) (setq inhibitmsg t) (call-interactively cmd) (setq win:kill-buffer-with win:current-config) (add-hook 'kill-buffer-hook 'win:kill-buffer-with-window))) ((and (string-match (char-to-string ans) "py") (null win:use-frame)) (win:switch-window window t t)) ((equal ans ?d) (require 'revive) (let ((conf (current-window-configuration-printable))) (win:switch-window window nil t) (restore-window-configuration conf))) ((string-match (char-to-string ans) "cy") (win:switch-window window nil t) (delete-other-windows) (switch-to-buffer (get-buffer-create "*scratch*"))) (nil t)) (or inhibitmsg (message "Memorize current window configuration into %c" (+ window win:base-key)))))) ))))) (defun win-menu (arg) "Windows menu for operations on window configuration." (interactive "p") (message "N)ext P)rv R)ecent D)el recoV)er K)ill S)ave2buf L)oad-from-buf saveA)s sW)ap") (let ((c (downcase (read-char)))) (cond ((= c ?n) (win-next-window arg)) ((= c ?p) (win-prev-window arg)) ((= c ?r) (win-recent-window)) ((= c ?v) (win-recover-recent-winconf arg)) ((= c ?d) (win-delete-current-window nil)) ((= c ?k) (win-delete-current-window t)) ((= c ?l) (win-load-window-buffer)) ((= c ?s) (win-update-window-buffer)) ((= c ?a) (win-save-as)) ((= c ?w) (call-interactively 'win-swap-with)) (t nil)))) ;; Interactive functions. (defun win-delete-current-window-force () (interactive) (win-delete-current-window t)) (defun win-load-window-buffer () (interactive) (win:set-wc win:current-config)) (defun win-update-window-buffer () (interactive) (win:store-config win:current-config) (message "Update window [%d]" win:current-config)) (defun win-save-as () (interactive) (let (c) (message "Save current window configuration into buffer # ?") (setq c (- (read-char) win:base-key)) (if (or (< c 1) (> c win:max-configs)) (error "Buffer number out of range")) (if (and win:use-frame ;;(aref win:configs c) ;;(frame-live-p (aref win:configs c)) (win:selected-window) ) (error "Window frame [%c] already used" (+ win:base-key c)) (win:store-config c) (win:switch-window c)) (message "Save current window configuration into buffer[%c]" (+ win:base-key c)))) (defun win-swap-with (win) "Swap current window configuration with WIN-th window's." (interactive "cSwap with: ") (if (or (< win win:base-key) (> win (+ win:base-key win:max-configs))) (error "Window number out of range")) (let* ((n (- win win:base-key)) (tmp (aref win:configs n)) conf1 conf2) (or tmp (error "Window [%c] is null." win)) (win:adjust-window) (if (= n win:current-config) (error "[%c] is current window." win)) (cond (win:use-frame (setq conf1 (current-window-configuration-printable)) (select-frame (aref win:configs n)) (setq conf2 (current-window-configuration-printable)) (restore-window-configuration conf1) (select-frame (aref win:configs win:current-config)) (restore-window-configuration conf2)) (t (aset win:configs n (win:current-window-configuration)) (win:set-window-name win:current-config) (aset win:names n (aref win:names win:current-config)) (win:set-window-configuration tmp)))) ) (defun win:read-config-file () "Read window configuration file from minibuffer." (let ((dir (file-name-directory win:local-config-file))) (setq dir (expand-file-name (read-file-name "Configuration file directory: " dir dir 1))) (if (not (string-match "[\\/]$" dir)) (setq dir (concat dir "/"))) (if (not (file-directory-p dir)) (error "No such directory [%s]" dir)) (setq win:local-config-file (concat dir (file-name-nondirectory win:configuration-file))))) (defun win-switch-task (force-save &optional config-file) "Switch to other configuration environments. If FORCE-SAVE is non-nil, save current environment without query. Optional second arg CONFIG-DIR specifies the configuration file to switch. Using from program, non-interactively, don't forget to specify second arg." (interactive "P") (if (or force-save (y-or-n-p (format "Save current configuration in [%s]? " win:local-config-file))) (let ((win:configuration-file win:local-config-file)) (win-save-all-configurations))) (let ((win:configuration-file (or config-file (win:read-config-file)))) (setq win:local-config-file win:configuration-file) (if (file-exists-p win:local-config-file) (win-load-all-configurations) (wipe-windows t) (message "New task started")))) (defun win-resume-local (arg) "Call resume operations with local configuration file." (interactive "P") (let (dir (win:configuration-file (win:read-config-file))) (win-resume-menu arg))) (defun win-resume-menu (&optional arg key) "Windows menu for resume operations." (interactive "P") (message "A)save-all R)esume-all S)ave-this L)oad-this N)Load# ~)read-~ W)ipe") (let ((c (or key (downcase (read-char))))) (win:adjust-window) (cond ((= c ?a) (win-save-all-configurations)) ((= c ?r) (win-load-all-configurations arg)) ((= c ?s) (win:save-window win:current-config)) ((= c ?l) (win:load-window win:current-config)) ((= c ?n) (message "Load the window No.?") (win:load-window (- (read-char) win:base-key))) ((= c ?~) (let ((win:configuration-file (make-backup-file-name win:configuration-file))) (win-load-all-configurations))) ((= c ?w) (require 'revive) (if (y-or-n-p "Do you wish to save this configurations? ") (let ((win:configuration-file (win:read-config-file))) (win-save-all-configurations))) (wipe-windows t)) ))) (defun win-toggle-window () "Toggle current window and most recently used one." (interactive) (win:adjust-window) (if (or (= win:last-config win:current-config) (equal (aref win:configs win:last-config) nil)) (message "No other window") (win:switch-window win:last-config))) (defun win-recent-window () "Switch to recently displayed window saved in temporary buffer. If Windows uses frame, switch to frame unallocated to Windows." (interactive) ;;(let ((last-wc (aref win:configs 0))(last-sz (aref win:sizes 0))) ;; (if last-wc (win:set-wc last-wc last-sz))) (if win:use-frame (let ((cf (selected-frame)) (frame (next-frame))) (if (catch 'found (while (not (eq frame cf)) (if (null (win:frame-window frame)) (throw 'found t)) (setq frame (next-frame frame)))) (progn (select-frame frame) (raise-frame frame) (win:focus-frame frame) (apply 'set-mouse-pixel-position (if win:xemacs-p (selected-window) frame) win:mouse-position) (win:update-mode-line 0)) (message "There are no %sunallocated frames for Windows." (if (win:frame-window (selected-frame)) "" "other "))) frame) (win:set-wc 0) (win:update-mode-line win:current-config))) (defun win-next-window (arg) "Switch to window saved in the ARG-th next configuration buffer." (interactive "p") (if (<= (win:No-of-windows) 1) (message "There is no other window.") (let ((count 0)(num win:current-config) (incr (if (> arg 0) 1 (1- win:max-configs)))) (setq arg (max arg (- arg))) (while (< count arg) (setq num (% (+ num incr) win:max-configs)) (if (and (aref win:configs num) (/= num 0)) (setq count (1+ count)))) (setq num (% num win:max-configs)) (if (= num win:current-config) (message "Next window by %d is this window." num) (win:switch-window num))))) (defun win-prev-window (arg) "Switch to window saved in the ARG-th previous congiguration buffer." (interactive "p") (win-next-window (- arg))) ;;;###autoload (defun win:set-wc (num) "(Windows low level internal) Set the NUM-th windows configuration. If Windows uses frame(Emacs 19), Select the NUM-th window frame." (let*((size (aref win:sizes num)) (oldh (nth 0 size)) (oldw (nth 1 size)) (wc (aref win:configs num))) (win:store-config 0) ;;save current configuration into array[0] (if win:use-frame (win:select-frame num) (win:set-window-configuration wc)))) (cond ((fboundp 'screen-height) (fset 'win:screen-height 'screen-height) (fset 'win:screen-width 'screen-width)) ((fboundp 'frame-height) (fset 'win:screen-height 'frame-height) (fset 'win:screen-width 'frame-width)) (t (error "I don't know how to run windows.el on this Emacs..."))) (fset 'win:focus-frame (cond ((fboundp 'focus-frame) 'focus-frame) ((fboundp 'x-focus-frame) 'x-focus-frame) (t (function (lambda (&rest ignore) nil))))) (defun win:store-config (index) "(Windows low level intenal)Save current configuration in INDEX-th of array." (aset win:configs index (if win:use-frame (selected-frame) (win:current-window-configuration))) (win:set-window-name index) (aset win:sizes index (list (win:screen-height) (win:screen-width)))) (defun win:current-window-configuration () (cons (current-window-configuration) (point-marker))) (defun win:set-window-configuration (wc) (prog1 (set-window-configuration (car wc)) (if (marker-buffer (cdr wc)) (progn (goto-char (cdr wc)) (set-marker (cdr wc) nil))))) (defun win:get-frame (index) "(windows internal) Get INDEX-th wnidows frame object" (let ((obj (aref win:configs index))) (if win:frames-in-nw (if obj (window-configuration-frame (car-safe obj)) (selected-frame)) obj))) (defun win:set-window-name (index) "(Windows low level intenal)Set current window name to INDEX-th of array." (require 'revive) (aset win:names index (mapconcat (function (lambda (w) (buffer-name (window-buffer w)))) (revive:window-list) " / "))) (defvar win:mode-string nil) (defun win:update-mode-line (number) "Update mode line for selected window number NUMBER." (let ((prefix (aref win:names-prefix number))) (setq win:mode-string (format win:mode-line-format (+ number win:base-key) (if (string= prefix "") "" ":") prefix ))) (set-buffer-modified-p (buffer-modified-p)) (sit-for 0)) (defun win-edit-name-prefix (index) "Edit win:names-prefix of INDEXth window." (interactive (list win:current-config)) (aset win:names-prefix index (read-string "Window name: " (aref win:names-prefix index))) (if (= win:current-config index) (win:update-mode-line index))) (defun win:recover-deleted-frames () "Detect frames deleted at initialization, and allocate new one for Windows. Do not call this function." (let ((i 1) newframe) (if (catch 'deleted (while (< i win:max-configs) (if (and (aref win:configs i) (not (frame-live-p (aref win:configs i)))) (throw 'deleted t)) (setq i (1+ i)))) (progn (aset win:configs i (setq newframe (win:allocate-frame i))) (modify-frame-parameters (aref win:configs i) '((name))) (select-frame newframe) (let ((index i)(frame newframe)) (run-hooks 'win:allocate-frame-hook)) (win:load-window i)) ))) ;;;###autoload (defun win:startup-with-window () "Start up Emacs with window[1] selected." (if (aref win:configs 1) nil (and (boundp 'default-frame-plist) ;for XEmacs initial variable (listp (car default-frame-plist)) (setq default-frame-plist (alist-to-plist default-frame-plist))) (cond ((and win:xemacs-p (lax-plist-get default-frame-plist 'minibuffer)) (win:remake-frame) (setq win:current-config 1) (win:store-config 1) (win:update-mode-line 1) (message "Startup with window [1]")) ((and win:use-frame (not (interactive-p))) ;; When called from .emacs, since the base frame at that time ;; will be deleted by the function frame-notice-user-settings, ;; allocating frame here won't work. So we set window-setup-hook to ;; do all the jobs after frame initialization has been done. (add-hook 'window-setup-hook (function (lambda () (if (aref win:configs 1) ;Already resumed by resume-windows ;; `emacs -e resume-windows' leads to this section. (progn (win:recover-deleted-frames) (if (get 'resume-windows 'lc) ;; Adjust window visiting list. ;; See also the comment of resume-windows. (let ((lc (get 'resume-windows 'lc))) (win:switch-window (car (cdr lc))) (put 'resume-windows 'lc nil) (setq win:last-config (car lc)) (message "Startup with window[%d]" win:current-config)))) (let ((count 30)) (while (and (null (visible-frame-list)) (> count 0)) (message "Waiting for frames to be shown...") (win:sit-for-a-while) (setq count (1- count)))) (select-frame (car (or (filtered-frame-list (function (lambda (f) (and (eq (cdr (assq 'visibility (frame-parameters f))) t) (not (member f (minibuffer-frame-list))))))) (visible-frame-list)))) (win:remake-frame) ;to change frame title with "mule[1]" (setq win:current-config 1) (win:store-config 1) (win:update-mode-line 1) (and (assq 'minibuffer default-frame-alist) (null (cdr (assq 'minibuffer default-frame-alist))) (boundp 'minibuffer-frame-alist) minibuffer-frame-alist (modify-frame-parameters (car (minibuffer-frame-list)) minibuffer-frame-alist)) (message "Startup with window [1]") (let ((index 1) (frame (aref win:configs 1))) (run-hooks 'win:allocate-frame-hook)) (sit-for 1)) 'append)))) (t ;not frame environment (win:store-config 1) (win:update-mode-line 1) (setq win:current-config 1) (message "Startup with window[1]"))))) ;;; ;; Functions for resume. ;;; (defconst win:revision "$Revision: 2.56 $" "Revision string of windows.el") (defvar win:revision-prefix ";win;") (defun win:frame-parameters (&optional frame) "Return frame parameters of FRAME (defaults to nil) which you want to save." (let ((parm (frame-parameters frame)) (tosave (append win:frame-parameters-to-save-default win:frame-parameters-to-save-private))) (delq nil (mapcar (function (lambda (s) (if (memq (car s) tosave) (if (and (eq 'minibuffer (car s)) (windowp (cdr s))) (cons 'minibuffer t) s)))) parm)))) (defun win:save-window (winnum) "Save window WINNUM into configuration file. Configuration to be saved is a list of (WINNUM (current-window-configuration-printable))" (require 'revive) (let ((conf (current-window-configuration-printable)) (make-backup-files win:make-backup-files) (version-control 'never) (hilit-auto-highlight nil) i) (set-buffer (find-file-noselect win:configuration-file)) (widen) (goto-char (point-min)) (if (re-search-forward "^([0-9]" nil t) (goto-char (match-beginning 0)) (goto-char (point-max)) (if (not (bolp)) (newline 1))) (if (re-search-forward (format "^(%d " winnum) nil t) (progn (goto-char (match-beginning 0)) (kill-sexp 1)) (catch 'here (while (re-search-forward "^(\\([0-9]+\\)" nil 1) (setq i (string-to-number (buffer-substring (match-beginning 1) (match-end 1)))) (if (> i winnum) (progn (open-line 1) (throw 'here t)))))) (if (not (bolp)) (newline 1)) (delete-blank-lines) ;; Now save the current window configuration. (insert (format "%s\n" (prin1-to-string (list winnum conf (if win:use-frame (win:frame-parameters (aref win:configs winnum))) (aref win:names-prefix winnum) ;;2.26 )))) (basic-save-buffer) (kill-buffer (current-buffer)) (message "Saved window [%d]" winnum))) ;;;###autoload (defun win-save-all-configurations () "Save all window configurations into the configuration file." (interactive) (message "Saving all window configurations") (require 'revive) (win:adjust-window) (win:store-config win:current-config) (let ((i 1) (buflist (revive:buffer-property-list)) (bakfile (concat win:configuration-file ".~~")) (hilit-auto-highlight nil) (version-control 'never)) (if (and win:make-backup-files (file-exists-p win:configuration-file)) (copy-file win:configuration-file bakfile t)) (set-buffer (find-file-noselect win:configuration-file)) (widen) (erase-buffer) (insert (format "%s%s\n\n" win:revision-prefix win:revision)) (insert (format ";;buffer-list\n%s\n\n;;window-configurations\n" (prin1-to-string (list buflist win:current-config win:last-config)))) (basic-save-buffer) (kill-buffer (current-buffer)) (while (< i win:max-configs) (if (aref win:configs i) (progn (if win:use-frame (progn (select-frame (aref win:configs i)) (or win:no-raise-at-save (raise-frame (aref win:configs i)))) (win:set-window-configuration (aref win:configs i))) (message "Saving window [%d]..." i) (win:save-window i) )) (setq i (1+ i))) (if (and win:make-backup-files (file-exists-p bakfile)) (let ((bk (make-backup-file-name win:configuration-file))) (rename-file bakfile bk t))) (message "Saved all configurations in [%s]" win:configuration-file) (if win:use-frame (win:select-frame win:current-config) (win:set-window-configuration (aref win:configs win:current-config))))) (defun win:load-window (arg) "Load the ARG-th window configuration from the configuration file." (require 'revive) (if (or (< arg 0) (> arg win:max-configs)) (error "Window number %d out of range" arg)) (if (null (file-exists-p win:configuration-file)) (error "Configuration file %s not found" win:configuration-file)) (let ((curb (current-buffer)) confb config) (set-buffer (find-file-noselect win:configuration-file)) (setq confb (current-buffer)) (widen) (goto-char (point-min)) (if (null (re-search-forward (format "^(%d " arg) nil t)) (error "Window [%s] is not found in configuration file." arg)) (goto-char (match-beginning 0)) (setq config (read (current-buffer))) (kill-buffer confb) (switch-to-buffer curb) (if (/= win:current-config arg) (win:switch-window arg nil t)) (win:set-frame-configuration config) (win:store-config win:current-config) (setq win:config-loaded t) (win:switch-window arg))) ;;;###autoload (defun wipe-windows (&optional no-ask) "Kill all buffers. Optional argument NO-ASK non-nil skips query." (interactive "P") (if (and (null no-ask) (not (y-or-n-p "Are you sure to wipe Emacs? "))) (error "Aborted")) (save-some-buffers) (let ((i 2)) (while (< i win:max-configs) (and win:use-frame win:wipe-also-frames (aref win:configs i) (delete-frame (aref win:configs i))) (aset win:configs i nil) (setq i (1+ i)))) (mapcar (function kill-buffer) (buffer-list)) (switch-to-buffer (get-buffer-create "*scratch*")) (funcall initial-major-mode) (delete-other-windows) (win:store-config 1) (win:update-mode-line 1)) (defun win:numericify (obj) "Force to numericify object of frame position parameter." (cond ((integerp obj) obj) ((and (listp obj) (= (length obj) 2) (memq (car obj) '(+ -))) (eval obj)) (t 100))) (defun win:set-frame-configuration (config) (if win:use-frame (let ((conf (car (cdr config))) x y (params (nth 2 config)) frame) ;;win:switch-window is the easiest way to resume frames. (win:switch-window (car config)) (setq frame (aref win:configs (car config))) (set-frame-width frame (car conf)) (set-frame-height frame (car (cdr conf))) (if (setq x (assq 'left params)) (setcdr (car (member x params)) (+ (win:numericify (cdr x)) win:resumed-frame-offset-x))) (if (setq y (assq 'top params)) (setcdr (car (member y params)) (+ (win:numericify (cdr y)) win:resumed-frame-offset-y))) (if win:xemacs-p ;XEmacs is unwilling to set minibuffer (setq params (delq (assq 'minibuffer params) params))) (modify-frame-parameters frame params)) (win:switch-window (car config) t t)) (if (nth 3 config) (aset win:names-prefix (car config) (nth 3 config))) (restore-window-configuration (car (cdr config)))) ;;;###autoload (defun win-load-all-configurations (&optional preserve) "Load all window configurations from the configuration file. Non-nil for optional argument PRESERVE keeps all current buffers." (interactive "P") (if (null (file-exists-p win:configuration-file)) (error "Configuration file %s not found" win:configuration-file)) (message "Loading all window configurations") (require 'revive) (let ((i 0) buflist wconflist buf) (if (null preserve) (wipe-windows t)) (if (aref win:configs 1) (win:switch-window 1)) (set-buffer (find-file-noselect win:configuration-file)) (setq buf (current-buffer)) (widen) (goto-char (point-min)) (if (null (search-forward win:revision-prefix nil t)) (error "Configuration file collapsed")) (if (and (not (string= win:revision (buffer-substring (point) (progn (end-of-line) (skip-chars-backward "^$") (point))))) (not (y-or-n-p "Configuration file version conflicts. Continue?"))) (error "Version of configuration file conflicts. Please update.")) (if (null (re-search-forward "^(" nil t)) (error "Configuration empty")) (goto-char (match-beginning 0)) (setq buflist (read (current-buffer))) (setq win:current-config (nth 1 buflist) win:last-config (nth 2 buflist)) ;;read all configs (while (re-search-forward "^([0-9]+ " nil t) (goto-char (match-beginning 0)) (setq wconflist (cons (read (current-buffer)) wconflist))) (setq wconflist (nreverse wconflist)) (set-buffer-modified-p nil) (kill-buffer buf) ;;Start restore (revive:restore-buffers (car buflist)) (while wconflist (message "Restoring window [%d]..." (car (car wconflist))) (let ((win:current-config win:current-config) win:last-config frame) (win:set-frame-configuration (car wconflist))) (win:store-config (car (car wconflist))) (win:restore-buffer-list (car (car wconflist))) (setq wconflist (cdr wconflist))) (win:set-wc win:current-config) (win:update-mode-line win:current-config) (setq win:config-loaded t)) (message "Finish loading. Resume in window [%d]" win:current-config)) (or global-mode-string (setq global-mode-string '(""))) (or (memq 'win:mode-string global-mode-string) (setq global-mode-string (append global-mode-string '(win:mode-string)))) ;;; ;; For Emacs 19 frame feature ;;; (defun win:select-frame (num) "Select the NUM-th window frame." (if (= (length (frame-list)) 1) (if (eq (selected-frame) (aref win:configs num)) (selected-frame) nil) (let ((goal (aref win:configs num))) (if (null (frame-live-p goal)) (aset win:configs num nil) ;returns NIL ;(if (eq (cdr (assq 'visibility (frame-parameters goal))) 'icon) ; (make-frame-visible goal)) ;to de-iconify(if iconified) ;;'visibility attribute is not defined in XEmacs... (or (eq t (frame-visible-p goal)) (make-frame-visible goal)) (or (frame-visible-p goal) (win:sit-for-a-while)) (raise-frame goal) (win:focus-frame goal) (if (fboundp 'select-frame-set-input-focus) (select-frame-set-input-focus goal) ;Emacs26 workaround (select-frame goal)) (if (not (eq (selected-frame) goal)) nil (and (fboundp 'unfocus-frame) (not win:xemacs-p) (unfocus-frame)) ;; Emacs-21.0.9x sometimes fails to display some part of frame (if (string< "21.0.92" emacs-version) (sit-for (string-to-number "1e-5"))) (apply 'set-mouse-pixel-position (if win:xemacs-p (selected-window) goal) win:mouse-position) goal))))) (defun win:selected-window () "Return the window number if selected-frame is a member of window list." (let ((i 1) (sf (selected-frame)) found) (while (and (< i win:max-configs) (not found)) (if (eq sf (win:get-frame i)) (setq found t)) (setq i (1+ i))) (if found (1- i)))) (defconst win:frames-in-nw (and (null window-system) (fboundp 'window-configuration-frame) ;not in XEmacs (fboundp 'make-frame) (string< "20" emacs-version)) "Flags whether using frame feature in -nw mode or not.") (defun win:adjust-window (&optional noerror) "Adjust win:current-config to (selected-frame). If optional argument NOERROR is non-nil, do not stop even if the selected window is not a member of window list." (interactive) (cond ((or win:use-frame win:frames-in-nw) (catch 'escape (if (eq (win:get-frame win:current-config) (selected-frame)) nil ;selected frame is current window. (let ((sw (win:selected-window))) (if (not sw) (if noerror (throw 'escape t) (error "This frame is not under control of windows.")) (setq win:last-config win:current-config win:current-config sw) (win:update-mode-line win:current-config)))) (if (and win:title-with-buffer-name (not win:xemacs-p) win:frame-title-function (not win:frames-in-nw)) (modify-frame-parameters nil (list (cons 'name (concat (funcall win:frame-title-function win:current-config) ":" (aref win:names-prefix win:current-config) "(" (buffer-name) ")"))))))))) (defun win:title-mode-line-updater () (if (eq this-command (get 'win:title-mode-line-updater 'last)) nil ;Continuous call(maybe) canceled (condition-case err (progn (win:adjust-window t) (put 'win:title-mode-line-updater 'buffer (current-buffer))) (error nil)))) (defun win:title-mode-line-updater2 () (if (eq this-command (get 'win:title-mode-line-updater 'last)) nil (put 'win:title-mode-line-updater 'last this-command) (or (eq (get 'win:title-mode-line-updater 'buffer) (current-buffer)) (condition-case err (progn (win:adjust-window t)) (error nil))))) (if (and win:use-frame win:need-uptodate-frame-title) (progn (add-hook 'pre-command-hook 'win:title-mode-line-updater) (add-hook 'post-command-hook 'win:title-mode-line-updater2))) (defvar win:memorized-winconf (make-vector win:max-configs nil) "Vector for temporary window-configurations of each frames.") (defun win:memorize-current-conf-1 () "(windows.el internal) Memorize recent window-configuration." (win:adjust-window t) (aset win:memorized-winconf win:current-config (win:current-window-configuration))) (defun win:memorize-current-conf (&optional from to old) "Memorize recent window-configuration. Called by after-change-functions" (if (or (eq (minibuffer-window) (selected-window)) (null (get-buffer-window (current-buffer))) (and (stringp (buffer-name)) ;;(string-match "^[ *]" (buffer-name)) ;;String-match causes error, why!!?? (memq (aref (buffer-name) 0) '(?* ? ?\t)))) t (win:memorize-current-conf-1)) nil) (defun win-recover-recent-winconf (arg) "Recover recent window configuration This is useful when some elisp destroys your editing window configuration. With prefix ARG non-nil, restore all window configuration including selected window. Without ARG, selected window and its point reserved." (interactive "p") (win:adjust-window) (let ((memorized (aref win:memorized-winconf win:current-config)) (sw (selected-window)) (ws (window-start)) (p (point))) (if (null memorized) (message "No conf. yet. Modify this buffer, and you get conf.") (aset win:memorized-winconf win:current-config (win:current-window-configuration)) (win:set-window-configuration memorized) (if (equal 1 arg) (progn (select-window sw) (set-window-start sw ws) (goto-char p)))))) (defvar win:memorize-winconf-timing 'save "*Timing of memorizing window configuration of selected frame. Choose one of 'save 'change. 'save Use write-file-hook. 'change Use after-change-functions.") (cond ((eq win:memorize-winconf-timing 'change) (add-hook 'after-change-functions 'win:memorize-current-conf nil)) ((eq win:memorize-winconf-timing 'save) (add-hook 'write-file-hooks 'win:memorize-current-conf nil))) ;(remove-hook 'after-change-functions 'win:memorize-current-conf nil) (defun win:adjust-names () "Adjust window names stored in win:names (for frame environment)." (cond (win:use-frame (let ((i 1)) (while (< i win:max-configs) (if (aref win:configs i) (progn (select-frame (aref win:configs i)) (win:set-window-name i))) (setq i (1+ i)))) (select-frame (aref win:configs win:current-config))))) (defun win:other-frame (arg) "Switch to other frame for windows." (interactive "p") (win:adjust-window t) (other-frame arg) (if (null (win:adjust-window t)) (win:update-mode-line 0))) (mapcar (function (lambda (s) (define-key global-map s 'win:other-frame))) (where-is-internal 'other-frame)) (defun win:frame-window (frame) "If FRAME is a member of window list return that index, else return nil." (let ((i 1)) (catch 'found (while (< i win:max-configs) (if (eq frame (aref win:configs i)) (throw 'found i)) (setq i (1+ i)))))) (defun win:allocate-frame (index) "Allocate a new frame for buffer list of Windows. If all frames are members of window buffer, create new frame. If there is a frame which don't belong to window buffer, return it. INDEX is referred to decide the frame position." (let ((flist (reverse (frame-list))) frame) (if (catch 'found (while flist (or (member (car flist) (minibuffer-frame-list)) (window-dedicated-p (frame-selected-window (car flist))) (if (null (win:frame-window (car flist))) (throw 'found (setq frame (car flist))))) (setq flist (cdr flist)))) frame (setq frame (win:make-frame index (if (and win:auto-position (numberp index) (memq 'top (append win:frame-parameters-to-save-default win:frame-parameters-to-save-private))) (let (frame (minn 1) minl mint left top) (cond ((eq win:auto-position 'absolute) (or (catch 'found ;search minimumly numbered window (while (< minn win:max-configs) (if (aref win:configs minn) (throw 'found t)) (setq minn (1+ minn)))) (setq minn 1 minl 0 mint 0)) ;not found (setq frame (aref win:configs minn) minl (cdr (assq 'left (frame-parameters frame))) minl (- (win:numericify minl) (* win:new-frame-offset-x (1- minn))) mint (cdr (assq 'top (frame-parameters frame))) mint (- (win:numericify mint) (* win:new-frame-offset-y (1- minn))) left (+ (* win:new-frame-offset-x index) minl) top (+ (* win:new-frame-offset-y index) mint))) (t ;not absolutely (setq left (cdr (assq 'left (frame-parameters (selected-frame)))) left (+ (win:numericify left) win:new-frame-offset-x) top (cdr (assq 'top (frame-parameters (selected-frame)))) top (+ (win:numericify top) win:new-frame-offset-y)))) (list (cons 'left left) (cons 'top top))))))) (run-hooks 'win:allocate-frame-hook) frame)) ;;; ;; For Utility ;;; ;;;###autoload (defun see-you-again () "Save all of the window configurations and kill-emacs." (interactive) (if win:current-config (progn (win-save-all-configurations) (message "See you again!") (sit-for 1) (save-buffers-kill-emacs)))) ;;;###autoload (defun resume-windows (&optional preserve) "Restore all window configurations reading configurations from a file. Non-nil for optional argument PRESERVE keeps current buffers." (interactive "P") (win:store-config 0) (win-load-all-configurations preserve) ;; This section depends highly on the version of `frame.el'. ;; It might be better to check boundp of variables frame-*. ;; But I think the case that those variables is not defined makes ;; confusion. So we refer them without checking boundp. (if (and win:use-frame (aref win:configs 1) frame-initial-frame (boundp 'frame-initial-geometry-arguments)) ;;Modify initial-frame-alist so that the alternative frame ;;which will be created by frame-notice-user-settings ;;has the same geometry as that of the resumed first frame. (let ((frame (aref win:configs 1))) (setq frame-initial-geometry-arguments (append (list (assq 'height (frame-parameters frame)) (assq 'width (frame-parameters frame)) (assq 'top (frame-parameters frame)) (assq 'left (frame-parameters frame))) frame-initial-geometry-arguments)) ;; The new frame created in frame-notice-user-settings is to ;; have the same buffer as that of selected frame at that time. ;; So we temporarily select the window#1 for the new frame, ;; and save the current window visiting list into the property ;; of the symbol 'resume-windows. (put 'resume-windows 'lc (list win:last-config win:current-config)) (win:switch-window 1)))) ;;; ;; Window selection menu ;;; (defvar win:switch-menu-buffer " * window list *") (defvar win:switch-menu-saved-config (make-vector 2 nil) "(windows internal variable) vector of [NUM CONF]; where NUM is the selected window number when window selection is invoked, CONF is the window configuration at the time.") (defun win-switch-menu-edit-name-prefix () "Edit win:names-prefix in win-switch-menu." (interactive) (let* ((goal (progn (beginning-of-line) (re-search-forward "(\\([A-Za-z0-9:-@]\\))" nil t) (- (char-after (match-beginning 1)) win:base-key))) (prefix (read-string "Window name: " (aref win:names-prefix goal)))) (if (> (length prefix) win:names-maxl) ;日本語知らない… (setq prefix (substring prefix 0 win:names-maxl))) (aset win:names-prefix goal prefix) (win:switch-menu-prepare-menu) (goto-char (point-min)) (search-forward (concat "(" (format "%c" (+ goal win:base-key)) ")")) (beginning-of-line) )) (defun win-switch-menu-select (kill) "Select the window of cursor position in *window list*. If interactive argument KILL is non-nil, kill menu buffer and no select." (interactive "P") (beginning-of-line) (if (and (eq (get-buffer win:switch-menu-buffer) (current-buffer)) (looking-at "[ A-Z]*(\\([A-Za-z0-9:-@]\\))")) (let ((goal (buffer-substring (match-beginning 1) (match-end 1)))) (setq goal (- (string-to-char goal) win:base-key)) (if win:use-frame (win:adjust-window)) (if (eq win:current-config (aref win:switch-menu-saved-config 0)) (win:set-window-configuration (aref win:switch-menu-saved-config 1))) (or kill (win-switch-to-window 1 goal))))) (defun win-switch-menu-select-directly () "Select the window directly from the keyboard in window selection menu." (interactive) (let ((num (- (win:last-key) win:base-key))) (and (eq (get-buffer win:switch-menu-buffer) (current-buffer)) (< num win:max-configs) (> num 0) (goto-char (point-min)) (progn (if win:use-frame (win:adjust-window)) (if (eq win:current-config (aref win:switch-menu-saved-config 0)) (win:set-window-configuration (aref win:switch-menu-saved-config 1))) (win-switch-to-window 1 num))))) (defun win-switch-menu-mark-job (unmark) "Put job symbol in window selection menu buffer." (interactive "P") (and (eq (get-buffer win:switch-menu-buffer) (current-buffer)) (progn (beginning-of-line) (looking-at "[ A-Z]+(.)")) (let (buffer-read-only) ;bound to nil (delete-char 1) (insert (if unmark " " (char-to-string (upcase (win:last-key))))) (forward-line 1) (and (eobp) (forward-line -1))))) (defun win-switch-menu-unmark-job () "Remove job symbol in window selection menu buffer." (interactive) (win-switch-menu-mark-job t)) (defun win-switch-menu-execute-job () "Do real jobs in window selection menu buffer." (interactive) (let*((current win:current-config) job num (name (aref win:names current)) (buf (get-buffer win:switch-menu-buffer)) (mes "Doing marked jobs...")) (save-excursion (goto-char (point-min)) (message mes) (while (re-search-forward "^[A-Z]" nil t) (setq job (char-after (match-beginning 0))) (re-search-forward "(\\([A-Za-z0-9:-@]\\))" nil t) (setq num (- (char-after (match-beginning 1)) win:base-key)) (cond ((= job ?D) (if (aref win:configs num) (if (or (/= current num) (y-or-n-p "Are you sure to kill this window?")) (win:delete-window num nil t)))) ;without query(3rd arg t) ((= job ?S) (and (aref win:configs num) (win:save-window num))) ((= job ?L) (let ((win:last-config win:last-config)) (win:load-window num) (if (= num current) ;override previous configuration. (aset win:switch-menu-saved-config 1 (win:current-window-configuration))))) ((= job ?K) (if (aref win:configs num) (let ((win:last-config win:last-config)) (win:switch-window num) (win-delete-current-window t)))) ;with query (t nil)) (and (aref win:configs num) (/= num current) (progn (win:switch-window current) ;back to menu buffer (win:set-window-name current))) ;preserve window name (set-buffer buf))) ;might be killed by `D' (message "%sDone." mes) (if (= current win:current-config) ;menu is still alive (win:switch-menu-prepare-menu)))) (defun win-switch-menu-quit () "Quit from window menu buffer." (interactive) (win-switch-menu-select t)) (defun win:switch-menu-prepare-menu () (switch-to-buffer win:switch-menu-buffer) (setq buffer-read-only nil) (erase-buffer) (let ((i 1) (this (make-marker)) (form (format " (%%c)%%s %%-%ds [%%s]\n" (+ win:names-maxl 2)))) (while (< i win:max-configs) (if (= win:current-config i) (set-marker this (point))) (insert (format form (+ win:base-key i) (cond ((= i win:current-config) "*") ((= i win:last-config) "+") (t " ")) (if (aref win:configs i) (format "\"%s\"" (aref win:names-prefix i)) "") (if (aref win:configs i) (aref win:names i) "") )) (setq i (1+ i))) (use-local-map win:switch-menu-map) (goto-char this)) (win:switch-menu-mode) (setq buffer-read-only t)) (defun win-switch-menu () "Show the menu of all windows and select one of them." (interactive) (if (string= (buffer-name (current-buffer)) win:switch-menu-buffer) () (if (= (+ win:current-config win:last-config) 0) (error "No windows allocated")) (win:adjust-window) (win:store-config win:current-config) ;save current state (win:adjust-names) (or win:use-frame (win:store-config win:current-config)) ;save current state (aset win:switch-menu-saved-config 0 win:current-config) (aset win:switch-menu-saved-config 1 (win:current-window-configuration)) (if (< (window-height) (1+ win:max-configs)) (enlarge-window (- win:max-configs (window-height))))) (win:switch-menu-prepare-menu) (message "N)ext P)rev SPC)select S)ave L)oad D)elete K)ill E)dit-name e(X)ec NUM Q)uit ?)help")) (defun win:switch-menu-mode () "===== Window selection buffer for windows.el ===== n next-line p previous-line \\[win-switch-menu-select] select this window \\[win-switch-menu-quit] quit from window selection menu NUMBER select NUMBER-th window directly s mark this window to be saved into configuration file l mark this window to be loaded from configuration file d mark this window to be deleted k mark this window to be killed (kill also displayed buffers) e edit window configuration name \\[win-switch-menu-execute-job] do jobs on each marked window " (setq major-mode 'win:switch-menu-mode mode-name "window selection")) (if (fboundp 'wrap-function-to-control-ime) (progn (wrap-function-to-control-ime 'win-menu t "p") (wrap-function-to-control-ime 'win-switch-to-window t "p") (wrap-function-to-control-ime 'win-resume-local t "P") (wrap-function-to-control-ime 'win-resume-menu t "P") (wrap-function-to-control-ime 'win-switch-menu t nil))) ;;; ;; Work-arounds ;;; ;for mew-5.2 or later (Suggested by masutaka) (if (fboundp 'defadvice) (defadvice mew-buffer-message (after mew-buffer-message-after-advice (&rest args) activate) (or win:use-frame (setq ad-return-value (format "%s%d" ad-return-value win:current-config))))) ;; Workaround for gnupack Emacs24.5 (and (string-match "24\\.5\\." (emacs-version)) (string-match "gnupack$" (emacs-version)) (fboundp 'wrap-function-to-control-ime) ;; Wrapping function of gnupack emacs24.5 breaks frame creation (add-hook 'term-setup-hook (function (lambda() (load "windows"))))) ;;; ;; Final setup. ;;; (provide 'windows) (run-hooks 'win-load-hook) ;; $Log: windows.el,v $ ;; Revision 2.56 2023/05/07 06:13:25 yuuji ;; Summary: Fix for focus-frame function ;; ;; Revision 2.55 2020/03/07 06:59:27 yuuji ;; Summary: Support emacs27(obsolete 'focus-frame) ;; ;; Revision 2.54 2019/11/04 01:57:24 yuuji ;; Update copyright line ;; ;; Revision 2.53 2018/06/02 06:55:03 yuuji ;; Summary: Possible workaround for Emacs26's behaviour of mouse-followed-focus ;; ;; Revision 2.52 2017/09/09 14:46:43 yuuji ;; Summary: License changed. ;; ;; Revision 2.51 2017/02/21 08:12:44 yuuji ;; Summary: Drop support of NEmacs - Emacs-18(string-to-int -> string-to-number) ;; ;; Revision 2.50 2017/01/16 00:09:57 yuuji ;; Workaround for Emacs 24.5 on gnupack. ;; Emacs 24.5 on gnupack does not update window status at "(sit-for 0)". ;; Instead, calling sit-for with 0.1sec. ;; (Thanks to masutani>atatat; ;; win:delete-frame-with-window : added ;; ;; #'win:delete-window : ;; if win:delete-frame-with-window is nil: ;; 1) do not delete the frame of the window ;; 2) do not call #'win:set-wc ;; ;; these changes have been tested, and appear to work well enough. ;; ;; (xemacs 21.5.4, with gtk widgets, might make some strange widgets appear ;; in the buffer that is selected after the key-sequence C-c C-w 9 c ) ;; ;; Revision 2.34 2002/01/29 14:09:21 yuuji ;; Call win:restore-buffer-list in win-load-all-configurations so that ;; buffer-list order in each window can be back at resume-windows. ;; ;; Revision 2.33 2001/10/28 07:57:49 yuuji ;; Emacs21 sometimes fails to locate new frame in expected position; fixed. ;; ;; Revision 2.32 2001/03/07 03:44:37 yuuji ;; Convert to EUC-JP for non-mule. ;; ;; Revision 2.31 2001/01/30 03:30:28 yuuji ;; For Emacs-21.0.96 in win:switch-window; ;; do win:restore-buffer-list after selecting target window(not frame mode) ;; ;; Revision 2.30 2001/01/29 09:06:10 yuuji ;; Sit-for 1e-10 in 2.29 is too little... Change to 1e-5. ;; ;; Revision 2.29 2001/01/29 09:04:02 yuuji ;; Emacs-21.0.9x sometimes fails to display some part of frame. ;; Add sit-for to win:selected-window for workaround. ;; ;; Revision 2.28 2001/01/24 12:57:54 yuuji ;; Check win:frame-title-function's void or not in win:adjust-window. ;; ;; Revision 2.27 2000/11/24 03:52:06 yuuji ;; Shorten window-creation message. ;; ;; Revision 2.26 1999/05/14 05:43:38 yuuji ;; Fix the case as below; ;; Start Emacs with win:startup-with-window, ;; and C-c 2 f SomeFile, ;; and immediately delete window by C-c !. it complain that ;; there is only one window. ;; ;; Revision 2.25 1999/01/16 06:19:25 yuuji ;; bug in win:store-buffer-list, fixed ;; ;; Revision 2.24 1999/01/16 05:13:20 yuuji ;; win:buffer-depth-per-win ;; preserves buffer-list priority per window ;; ;; Revision 2.23 1998/11/12 13:42:01 yuuji ;; Now runs correctly on Emacs without screen-height/screen-width. ;; ;; Revision 2.22 1998/10/26 13:25:02 yuuji ;; For Emacs20, avoid infinite loop at selecting iconified frame. ;; ;; Revision 2.21 1998/09/22 15:16:08 yuuji ;; Now win:auto-position works correctly on Emacs20. ;; ;; Revision 2.20 1998/09/22 14:46:29 yuuji ;; *** empty log message *** ;; ;; Revision 2.19 1998/04/01 03:52:24 yuuji ;; FSF's address fixed ;; ;; Revision 2.18 1997/12/22 02:34:04 yuuji ;; win:wipe-also-frames works correctly ;; ;; Revision 2.17 1997/12/15 02:52:55 yuuji ;; Free variable `frame' in win:set-frame-configuration localized ;; ;; Revision 2.16 1997/12/08 06:51:52 yuuji ;; Small fix ;; ;; Revision 2.15 1997/12/08 06:43:15 yuuji ;; Try to keep frame title up to date. ;; win:need-uptodate-frame-title ;; ;; Revision 2.14 1997/12/04 03:30:27 yuuji ;; win:wipe-also-frames ;; Set win:current-config to 1 at win:startup-with-window. ;; ;; Revision 2.13 1997/12/01 19:36:53 yuuji ;; Fix document of the part which says about combination with window ;; manager. ;; ;; Revision 2.12 1997/12/01 01:51:28 yuuji ;; Switch to selected frame at loading. ;; Don't pass 'minibufffer property at frame creation on XEmacs. ;; ;; Revision 2.11 1997/11/29 13:19:42 yuuji ;; XEmacs support ;; ;; Revision 2.10 1997/10/23 13:53:52 yuuji ;; Support Emacs20 ;; ;; Revision 1.94 1997/01/27 03:50:31 yuuji ;; split-window-safe fixed ;; mew support fixed again ;; ;; Revision 1.93 1997/01/17 03:10:38 yuuji ;; Support mew(revive.el) ;; ; Revision 1.92 1996/08/16 16:23:18 yuuji ; Adjust window at win-resume-menu and win-swap-with. ; ; Revision 1.91 1996/05/05 16:48:50 yuuji ; small fix for emacs 19.30 ; ; Revision 1.9 1995/09/07 02:27:16 yuuji ; Revise document. ; ; Revision 1.8 1995/07/13 01:33:19 yuuji ; Fix typos and setq of frame-initial-geometry-arguments. ; ; Revision 1.7 1995/02/02 17:37:05 yuuji ; New variables for customization, win:resumed-frame-offset-x, ; win:resumed-frame-offset-y and win:mouse-position added. ; ; Revision 1.6 1995/01/12 14:55:37 yuuji ; Enhanced window selection menu ; ; Revision 1.5 1994/11/19 17:50:30 yuuji ; Resume window number correctly when splitting minibuffer. ; ; Revision 1.4 1994/09/26 17:16:09 yuuji ; Full support for Emacs-19. ; ; Revision 1.3 1994/06/06 07:51:52 yuuji ; Window #0 no longer shows up in window-list. ; ; Revision 1.2 1994/05/06 21:38:33 yuuji ; Omit window#0 on win-{next,prev}-window. ; Disable deleting sole window. ; win:last-config has no longer #0. ; ; Revision 1.1 1994/04/18 02:41:22 yuuji ; Fix the bug on `Preserve' of window creation menu. ; ; Revision 1.0 1994/03/07 07:39:01 yuuji ; Support `frame environment' of Emacs 19. ; ; Revision 0.9 1994/02/17 08:48:41 yuuji ; Make win-startup-with-window smart. ; Local resume. ; ; Revision 0.8 1994/02/09 10:57:20 yuuji ; Update the document. ; Fix win:startup-with-window. ; ; Revision 0.7 1994/02/07 12:41:05 yuuji ; win-resume-menu ; ; Revision 0.6 1994/02/05 07:56:37 yuuji ; Add the functions to resume Emacs. ; ; Revision 0.5 1994/02/03 10:08:03 yuuji ; Allow resize of Emacs's window. ; ;; Revision 0.2 93/10/12 02:43:15 yuuji ;; Change prefix key to `C-c C-w'. ;; ; Local variables: ; fill-prefix: ";;; " ; paragraph-start: "^$\\| \\|;;;$" ; paragraph-separate: "^$\\| \\|;;;$" ; End: