;;; -*- Emacs-Lisp -*- ;;; Window manager for GNU Emacs. ;;; $Id$ ;;; (c ) 1993,1994 by HIROSE Yuuji [yuuji@ae.keio.ac.jp] ;;; Last modified Thu Sep 22 14:02:25 1994 on pajero ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ;;; Window manager for GNU Emacs ;;; ;;;[What is Windows?] ;;; ;;; You can divide the screen of GNU Emacs as many as you like. ;;; Since efficiency of implementation or so depends much on the ;;; style of window division, you may have your own style of ;;; partitioning. But if you switch the mode to e-mail mode or ;;; NetNews mode, they break your favorite style. ;;; Windows.el enables you to have multiple favorite window ;;; configurations at the same time, and switch them. Furthermore, ;;; it can save all window configurations into a file and restore ;;; them correctly. ;;; ;;; **For Emacs 19** ;;; ;;; This package provides the `named(numbered) frame' that can be ;;; selected directly with their name. With revive.el, all frames' ;;; displaying buffers, window configurations and size can be saved ;;; and restored. ;;; ;;;[Installation] ;;; ;;; Put windows.el into the directory load-path indicates, and put ;;; the following expressions into your ~/.emacs. ;;; ;;; (require 'windows) ;;; (win:startup-with-window) ;;; (define-key ctl-x-map "C" 'see-you-again) ;;; ;;; If you don't want Emacs to start up always with Windows, use ;;; the following expressions instead of above. ;;; ;;; (autoload 'win-switch-to-window "windows" "Switch window." t) ;;; (autoload 'win-show-window-list "windows" "List window." t) ;;; (define-key global-map "\C-c\C-w1" 'win-switch-to-window) ;;; (define-key global-map "\C-c1" 'win-switch-to-window) ;;; (define-key ctl-x-map "C" 'see-you-again) ;;; ;;;[Key Bindings] ;;; ;;; The default prefix key stroke for Windows is `C-c C-w'. If it ;;; causes you some troubles, see the section `Customizations'. ;;; Here are the default key bindings. ;;; ;;; C-c C-w 1 Switch to window 1 (Q) ;;; C-c C-w 2 Switch to window 2 (Q) ;;; : ;;; C-c C-w 9 Switch to window 9 (Q) ;;; C-c C-w 0 Swap windows with the buffer 0 (Q) ;;; (Select unallocated frame(Emacs 19)) ;;; C-c C-w SPC Switch to window previously shown (Q) ;;; C-c C-w C-n Switch to next window ;;; C-c C-w C-p Switch to previous window ;;; C-c C-w ! Delete current window (Q) ;;; C-c C-w C-w Window operation menu ;;; C-c C-w C-r Resume menu ;;; C-c C-w C-l Local resume menu ;;; C-c C-w C-s Switch task ;;; C-c C-w = Show window list (Q) ;;; ;;; The key strokes to select windows from 1 to 9 must be ;;; frequently used, so the alternative key strokes `C-c [Num.]' are ;;; available by default (And any function with (Q)mark can be ;;; invoked without C-w). To disable these quick key strokes, set ;;; the variable win:quick-selection to `nil' in your ~/.emacs. ;;; ;;;[Description] ;;; ;;; Windows.el has 10 window buffers, from 0 to 9. But you can ;;; use the buffer from 1 to 9, the buffer 0 is reserved for the ;;; most recently used window (This is not true for the frame ;;; environment of Emacs 19). ;;; ;;; If you have wrote `win:startup-with-window' in your .emacs, ;;; the initial window configuration is memorized in the buffer 1. ;;; Otherwise you have to memorize it by typing `C-c C-w 1'. ;;; Anyway, say you are editing some program in buffer 1. ;;; ;;; After a while, a mail has arrived. You may wish to assign a ;;; mail mode configuration to the buffer 2. Type `C-c C-w 2' to ;;; create the buffer 2, and you will see the `window creation ;;; menu': ;;; ;;; C)reate D)uplicate P)reserve F)indfile B)uff X)M-x N)o: ;;; ;;; in the minibuffer. Since you don't need the current window ;;; configuration (programming configuration) to read mails, type ;;; `c', stands for Create, to create the new window configuration. ;;; Then, after invoke the mail reader, current window configuration ;;; will turn to mail oriented one. (Of course you can directly call ;;; e-mail mode by typing `x' at the window creation menu.) When you ;;; finish to read your mail, you can return to programming ;;; configuration with `C-c C-w 1'. ;;; ;;; Let's read the NetNews. M-x gnus... O.K.! You've read. You ;;; may have typed `q' to quit gnus until yesterday. But you don't ;;; have to do it from today. You can go back to programming ;;; immediately by typing `C-c C-w 1'! Oops, you have not created ;;; the new configuration buffer yet. So the window you see is ;;; still the window 1. If you switch the window to another, you'll ;;; lose the configuration in the buffer 1. In this case, type `p' ;;; (stands for Preserve) at the window creation menu after typing ;;; `C-c C-w 3'(%1). Windows.el doesn't update the buffer 1 and ;;; saves the current window configuration of the NetNews into the ;;; buffer 3. ;;; **On Emacs-19, you can't preserve the buffer contents unless you ;;; have saved it into the resume file described below. ;;; ;;; Then, type `C-c C-w 2' to read the mail, type `C-c C-w 3' when ;;; you are tired with programming. `C-c C-w SPC' is very ;;; convenient when you want to exchange two configurations. ;;; ;;; If you forget what screens are allocated to the buffers, type ;;; `C-c C-w =' to display the configuration buffer names and their ;;; corresponding editing buffer names in the minibuffer. The entry ;;; preceded by `*' is the selected buffer and the entry with `+' is ;;; the buffer previously selected(that is, the buffer `C-c C-w SPC' ;;; will select). ;;; ;;; (%1) ;;; At a point of this time, while window configuration buffer holds ;;; the programming environment, the screen of GNUS is displayed. ;;; And, notice that `p'(Preserve) at the window creation menu ;;; doesn't work when the Windows uses `frame' as window unit on ;;; Emacs 19. ;;; ;;;[Other functions] ;;; ;;; Typing `C-c C-w C-w' displays the menu as follows. ;;; ;;; N)ext P)rev R)ecent D)elete K)ill S)ave2buf L)oad-from-buf A)save-As ;;; ;;; In this menu, `n', `p' is for switching window to the next or ;;; previous, `r' is for recovering the window recently seen before ;;; the window switching operation(%2), `d' is for deleting current ;;; window. `k' is same as `d' except closing all visible file(s). ;;; And type `s' to save the current window configuration into the ;;; corresponding buffer, `a' to save the current window ;;; configuration into specified buffer. ;;; ;;; (%2) ;;; When using frame on Emacs 19, it is impossible to store a frame ;;; recently seen, so `r' (win-recent-window) selects a frame that ;;; is not allocated to Windows instead, if any (equivalent to `C-c ;;; C-w 0'). ;;; ;;; When you create the new window, you see the window creation ;;; menu which ask you how to handle the current configuration ;;; buffer and what configuration the new window must be. The ;;; entries of the prompt stand for the followings. ;;; ;;; Create After saving the current window ;;; configuration into the current buffer, ;;; create a newly allocated window. ;;; Duplicate After saving the current window ;;; configuration into the current buffer, ;;; create the new window with the same ;;; configuration as the current one. ;;; Preserve Without updating the current buffer, ;;; use the current window configuration ;;; as the new window. This function is not ;;; available on Emacs 19 with frame. ;;; Findfile Find-file on new window. ;;; Buff Switch to buffer on new window. ;;; M-x Call a command on new window. ;;; No Cease window creation. ;;; ;;;[Resume] ;;; ;;; Windows.el can resume your environment with a help of ;;; `revive.el'. You can see the menu by typing `C-c C-w C-r'. ;;; ;;; A)save-all R)estore-all S)ave-this L)oad-this N)Load# ~)read-~ ;;; ;;; Type `a' to save all window configurations into a file, and type ;;; `r' to restore configurations saved in that file. `s' to save ;;; the current window configuration, `l' to load current window ;;; from file, `n' to load a window specified by a number. And use ;;; `~' when you type `a' instead of `r' by mistake. And it is much ;;; more convenient to kill emacs with `C-x C'. If you want to ;;; resume that context, call `resume-windows' (or C-c C-w C-r r) ;;; just after starting Emacs. ;;; ;;;[Local resume] ;;; ;;; If you want to have many sets of window configurations, type ;;; `C-c C-w C-l' to specify the directory where another ;;; configuration file is to resid, and operate in the same way as ;;; you do in resume menu described above. You can change sets of ;;; configurations directory by directory. ;;; ;;; By the way, most of tasks are being done in a certain ;;; directory. If you have a couple of or more jobs to do at once, ;;; the function `win-switch-task' is very useful to switch your ;;; tasks. It saves the current set of window configurations into ;;; current configuration file, flushes buffers, and reads the next ;;; set of window configurations for the next task from another ;;; configuration file. ;;; ;;;[Customizations] ;;; ;;; To change the prefix key stroke to `C-c w' for example, ;;; put the following expressions into your ~/.emacs. ;;; ;;; (setq win:switch-prefix "\C-cw") ;;; (define-key global-map win:switch-prefix nil) ;;; (define-key global-map "\C-cw1" 'win-switch-to-window) ;;; ;;; And you can also change the key stroke of window selection to ;;; `a' to `z' other than `1' to `9'. ;;; ;;; (setq win:switch-prefix "\C-cw") ;;; (define-key global-map win:switch-prefix nil) ;;; (define-key global-map "\C-cwb" 'win-switch-to-window) ;;; (setq win:base-key ?`) ;; '`' is before 'a' ;;; (setq win:max-configs 27) ;; '`' to 'z' are 27 chars. ;;; (setq win:quick-selection nil) ;; Not assign `C-c LETTER' ;;; ;;; Notice that '`' is the previous character of 'a' in ASCII code, ;;; and that C-c w ` is bound to swap the configuration in the ;;; buffer '`' and the current buffer. ;;; ;;; If you don't use `frame' even on Emacs 19 with X Window. Set ;;; win:use-frame to nil in ~/.emacs. ;;; ;;; If you hate raising of frames at win-save-all-configurations, ;;; set win:no-raise-at-save to t. ;;; ;;;[For frame users] ;;; ;;; When you start to use windows.el, you may create a new frame ;;; with old operation `C-x 5 f' or so. Frames created with ;;; standard frame operation are not marked in the windows ring. To ;;; incorporate sucn an orphan frame into windows ring, type `C-c ;;; C-w C-w' and select `A)save-as' from the menu. And if you want ;;; to switch to orphan frames, type `C-c C-w 0', which switches ;;; frame to isolated frames and rotate them. ;;; ;;;[Bugs] ;;; ;;; This program was inspired from `screen', the window manager ;;; for VT100 emulation terminal, and operations are fundamentally ;;; based on it. But there is no compatibility. ;;; ;;; When restoring frames of Emacs 19, the order of frame ;;; allocation is not restored, that is, its order depends on the ;;; frame where win-load-all-configurations is called. No frame ;;; positions are not recovered neither. ;;; ;;;[Copying] ;;; ;;; This program is distributed as a free software. The author is ;;; not responsible for any possible defects caused by this ;;; software. ;;; ;;; Comments and bug reports are welcome. Don't hesitated to ;;; report. My possible e-mail address is following. ;;; ;;; yuuji@ae.keio.ac.jp ;;; pcs39334@asciinet.or.jp ;;; ;;; Japanese Document follows: ;;; ;;; GNU Emacs 用編集画面マネージャ [windows] ;;; ;;;【できる事】 ;;; ;;; GNU Emacs では縦横任意の数だけウィンドウを分割して作業をする事 ;;; ができます。プログラムを開発する時などのウィンドウ分割は効率に大 ;;; きく影響するので、人によって好みの分割形態を持っている事でしょう。 ;;; しかしその途中で、メイルやニュースを読むとその分割形態を壊されて ;;; しまいます。正しい手順でメイルリーダモードを終われば良いのですが、 ;;; それだとまたメイルが来た時に再びメイルリーダモードを起動しなけれ ;;; ばなりません。 ;;; windows.el をロードすると、好みのウィンドウ分割形態を複数持ち、 ;;; それらを切替えながら Emacs を使う事ができます。さらに、その分割 ;;; 形態の全てをファイルにセーブし、いつでもそれらを復元することがで ;;; きます。 ;;; ;;; Emacs 19(Mule2) では、同様の操作体系で frame を単位としてウィ ;;; ンドウ切替え操作を行います。さらに分割形態復元時にはフレームのサ ;;; イズと位置も忠実に再現します。 ;;; ;;;【準備】 ;;; ;;; windows.el を load-path の通ったディレクトリに入れてください。 ;;; そして以下の行を .emacs に入れてください。 ;;; ;;; (require 'windows) ;;; (define-key global-map "\C-xC" 'see-you-again) ;;; (win:startup-with-window) ;;; ;;; もし必ずしも windows を利用しないことがある場合は、上の記述で ;;; はなく以下のように書くと良いでしょう。 ;;; ;;; (autoload 'win-switch-to-window "windows" "Switch window." t) ;;; (autoload 'win-show-window-list "windows" "List window." t) ;;; (define-key global-map "\C-c\C-w1" 'win-switch-to-window) ;;; (define-key global-map "\C-c1" 'win-switch-to-window) ;;; (define-key ctl-x-map "C" 'see-you-again) ;;; ;;; ;;;【キー定義】 ;;; ;;; デフォルトのプリフィクスキーは C-c C-w です。これでは不都合な ;;; 場合は『キーカスタマイズ』の項を参照してください。標準状態のキー ;;; バインドは以下のようになっています。 ;;; ;;; C-c C-w 1 分割状態 1 へ (Q) ;;; C-c C-w 2 分割状態 2 へ (Q) ;;; : ;;; C-c C-w 9 分割状態 9 へ (Q) ;;; C-c C-w 0 直前の分割状態へ(バッファ0と交換) (Q) ;;; C-c C-w SPC 分割状態1〜nのうち、直前用いたものへ (Q) ;;; C-c C-w n 次の分割状態へ(C-c SPC) ;;; C-c C-w p 前の分割状態へ ;;; C-c C-w ! 現在のウィンドウを破棄 (Q) ;;; C-c C-w C-w ウィンドウ操作メニュー ;;; C-c C-w C-r リジュームメニュー ;;; C-c C-w C-l ローカルリジュームメニュー ;;; C-c C-w C-s タスク切替え ;;; C-c C-w = 分割状態保存バッファ一覧表示 (Q) ;;; ;;; 1 番から 9 番までのウィンドウ選択は非常に頻繁に用いられるので、 ;;; 「C-c 番号」でも切り替えができるようになっています(その他Qマーク ;;; の付いているキーバインド全ては C-w を打たなくてもよい)。これを無 ;;; 効にするためには、~/.emacs などで変数 win:quick-selection を nil ;;; にセットしてください。 ;;; ;;;【説明】 ;;; ;;; windows.el には0から9までの10個のバッファが用意されています。 ;;; このうちユーザが好みの分割状態を保存させるために使えるのは1〜9 ;;; で、0番は自動的に直前の分割状態をセーブするために使われます ;;; (Emacs-19ではwindowsに割り当てられていないframeへのジャンプ)。 ;;; ;;; win:startup-with-window を .emacs に書いている場合は起動時の編 ;;; 集状態がそのまま1番のバッファに格納されています。そうでない場合 ;;; は何か C-c C-w 1 を押して最初の編集状態を1番のバッファに記憶させ ;;; ます。 ;;; ;;; さて、1番に現状を保存した状態で、メイルを読みましょう。メイル ;;; は2番のウィンドウに割り当てます。C-c C-w 2 を押すと今度は ;;; ;;; C)reate D)uplicate P)reserve F)indfile B)uff X)M-x N)o: ;;; ;;; と出て来ます(これをウィンドウ生成メニューと呼ぶことにします)。メ ;;; イルを読むためには現在の分割状態は必要ありませんから、Create の ;;; c を押して新規ウィンドウを作成します。そこでメイルリーダを起動す ;;; ると、ウィンドウの分割状態がメイル専用になります(もちろんメニュー ;;; でxを押して直接メイルリーダを起動してもかまいません)。読み終わっ ;;; たら C-c C-w 1 を押すと、1番のバッファに保存されている、最初のプ ;;; ログラム編集状態に切り替わります。これでプログラム作成に直ちに戻 ;;; れます。 ;;; ;;; 今度はニュースを読みましょう。M-x gnus ・・・。はい読み終わり ;;; ました。いままでは q で終了していましたが、今日からは違います。 ;;; C-c C-w 1 で復帰できるのです。はい、C-c C-w 1。おっと、新規ウィ ;;; ンドウを作成するのを忘れていたので、まだ1番のウィンドウにいたの ;;; でした。このまま(%1)ではせっかく1番に保存したプログラム編集状態 ;;; が消えてしまいます。そんな時は、C-c C-w 3 を押してウィンドウ生成 ;;; メニューが出たところで、Preserve の p を押してください。1番のバッ ;;; ファの内容は更新せずに、現状のウィンドウ状態を3番のバッファに保 ;;; 存します。 ;;; **Mule2ではリジューム(後述)ファイルに現在の状態がセーブされていな ;;; い限り、分割状態を復旧することができません。 ;;; ;;; あとはメイルが来たら C-c C-w 2 を、プログラムに飽きたら C-c ;;; C-w 3 を押して一日を過ごしましょう。メイルとニュースだけを読み続 ;;; ける場合のように二つの状態を行ったり来たりする場合は C-c C-w SPC ;;; が便利です。 ;;; ;;; 「あれ、メイルはいま何番のウィンドウだ?」と分からなくなったら、 ;;; C-c C-w = を押しましょう。ミニバッファに番号と、対応するバッファ ;;; 名が表示されます。このうち、 番号の頭に*が付いているものが現在選 ;;; 択しているバッファで、+が付いているものが直前に選択していたバッ ;;; ファです(つまり C-c C-w SPC の行き先)。 ;;; ;;; (%1) ;;; この状態ではバッファにプログラム編集状態が保存され、ウィンドウに ;;; GNUSの画面が表示されている。なお、Preserve は Emacs 19 でframeを ;;; 切替え単位とする場合には利用できないので注意して下さい。 ;;; ;;;【その他細かい機能】 ;;; ;;; C-c C-w C-w を押すと以下のようなメニューが出て来ます。 ;;; ;;; N)ext P)rev R)ecent D)elete K)ill S)ave2buf L)oad-from-buf A)save-As ;;; ;;; n, p はそれぞれ一つ前/次のバッファの選択します。r はウィンドウ切 ;;; り替えする直前に表示していた画面へ復帰します(%2)。d は現在選択し ;;; ている番号のバッファを消去します。k は d と同じですが、現在見え ;;; ているファイルも同時にクローズします。l は間違えて C-x 1 してし ;;; まった時などに、バッファにセーブされているウィンドウ状態を強制的 ;;; に読み直す時に使います。s は現在見ている状態を強制的に対応するバッ ;;; ファにセーブする為に使い、a はセーブするバッファ番号を別途指定す ;;; る時に使います。 ;;; ;;; (%2) ;;; Emacs 19 の frame 機能でウィンドウ切替えを行う場合、直前の状態を ;;; 保存する事はできないため、r を押した場合(関数win-recent-window) ;;; windows 用に割り当てられていない frame があればそれに表示を切替 ;;; えます(C-c C-w 0 と同じ)。 ;;; ;;; 新規ウィンドウ作成時に、現在のバッファ内容の更新と、新ウィンド ;;; ウの状態を指示するためにウィンドウ生成メニューが出ます。これらの ;;; 意味は以下のようになっています。 ;;; ;;; Create 現画面を現バッファに保存後、新規ウィンド ;;; ウを生成 ;;; Duplicate 現画面を現バッファに保存後、現画面と同じ ;;; ウィンドウを生成 ;;; Preserve 現バッファは更新せず、現画面を新規ウィン ;;; ドウとして登録 ;;; Findfile 新規ウィンドウで find-file を行なう ;;; Buff 新規ウィンドウで switch-to-buffer を行なう ;;; M-x 新規ウィンドウでコマンド実行 ;;; No 新規ウィンドウ生成を中止 ;;; ;;;【リジューム】 ;;; ;;; revive.el と組み合わせて使うことにより、リジューム機能が有効で ;;; す。C-c C-w C-r を押すと以下のメニューが現れます。 ;;; ;;; A)save-all R)estore-all S)ave-this L)oad-this N)Load# ~)read-~ ;;; ;;; ここで a を押すと現在の全てのウィンドウの情報をファイルにセーブ ;;; することができます。r を押すとファイルにセーブしたものをロードす ;;; ることができます。s,l を押すと現在選択しているウィンドウ状態をそ ;;; れぞれ セーブ/ロード します。n はファイルから数字で指定したウィ ;;; ンドウ状態をロードします。また Emacs 起動直後に r を押すところを ;;; 間違えて a を押してしまった場合などは ~ を利用してください。 ;;; ;;; このメニューからセーブするよりも「C-x C」で Emacs を終了し、次 ;;; 回 Emacs を起動した直後に resume-windows (または C-c C-w C-r r) ;;; を起動することで直ちに以前の状態に戻ることができるのでこちらの方 ;;; が便利な使い方といえましょう。 ;;; ;;;【ローカルリジューム】 ;;; ;;; リジュームでは全てのウィンドウ情報をファイルにセーブしますが、 ;;; そのファイルをさらに複数持ち、それぞれを切り替えて使うことができ ;;; ます。「C-c C-w C-l」をタイプし情報ファイルをセーブ/ロードするデ ;;; ィレクトリを入力した後、通常のリジュームメニューの操作を行ないま ;;; す。 ;;; ;;; ところで、多くの仕事はその仕事特有のディレクトリをベースに行わ ;;; れます。この性質を利用して、一度に複数個の仕事をこなす場合などに、 ;;; 関数 win-switch-task を使うと仕事の切替えをスムーズに行うことが ;;; できます。この関数を呼ぶと現在の環境を現在の情報ファイルに保存す ;;; るか確認後、次の仕事を行っているディレクトリの入力を促します。 ;;; ;;;【キーカスタマイズ】 ;;; ;;; プリフィクスキーを例えば C-c w に変更する時は .emacs に次のよ ;;; うな記述をいれます。 ;;; ;;; (setq win:switch-prefix "\C-cw") ;;; (define-key global-map win:switch-prefix nil) ;;; (define-key global-map "\C-cw1" 'win-switch-to-window) ;;; ;;; ウィンドウの選択を1〜9ではなくて、a〜zにすることもできます。 ;;; ;;; (setq win:switch-prefix "\C-cw") ;;; (define-key global-map win:switch-prefix nil) ;;; (define-key global-map "\C-cwa" 'win-switch-to-window) ;;; (setq win:base-key ?`) ;; ` は「直前の状態」 ;;; (setq win:max-configs 27) ;; ` 〜 z は27文字 ;;; (setq win:quick-selection nil) ;; C-c英字 に割り当てない ;;; ;;; ここで ` はアスキーコードで a の一つ前にあることに注意してくださ ;;; い。C-c C-w ` は直前状態保存用バッファと、カレントウィンドウの内 ;;; 容の交換に割り当てられます。 ;;; ;;;【バグ】 ;;; ;;; ウィンドウを切替えると言うアイデアは screen コマンドに基づいて ;;; いますが、操作体系は完全に同じではありません。 ;;; ;;;【あとがき】 ;;; ;;; 似たようなの他にもありそう。というわけで fj.editor.emacs に投 ;;; 稿したところ screens.el というまさに screen コマンド互換のものが ;;; ありました。しかし screens はウィンドウ切替え前に Emacs のサイズ ;;; を変えると復元がうまく行かないようですが、windows では(とくに工 ;;; 夫はしていませんが)うまくできます。さらに全ウィンドウ状態の保存/ ;;; 復元を可能にしたので、論文にインプリメントにと忙しい時期には欠か ;;; せないユーティリティとなるでしょう。 ;;; ;;;【謝辞】 ;;; ;;; このプログラムを作るきっかけと適切なコメントを下さった、ASCII- ;;; NETのたりゃー佐々木さん、 Emacs-19 でミニバッファを分離させてい ;;; る時の挙動に関するデバッグに協力下さったfujixerox.co.jpの廣瀬陽 ;;; 一さんに感謝致します。 ;;; ;;;【取り扱い】 ;;; ;;; このプログラムは、フリーソフトウェアといたします。このプログラ ;;; ムを使用して生じたいかなる結果に対しても作者は一切の責任を負わな ;;; いものといたしますが、コメントやバグレポートは大いに歓迎いたしま ;;; す。お気軽にご連絡下さい。連絡は以下のアドレスまでお願いいたしま ;;; す(1995/3現在)。 ;;; yuuji@ae.keio.ac.jp ;;; pcs39334@asciinet.or.jp ;;; ;; Code ;;; ;; ---------- Customizable variables (defvar win:max-configs 10 "*Number of window configurations to hold.") (defvar win:base-key ?0 "*Base of window buffer name.") (if (> 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]" "*Format of mode line that shows the selected window number.") (defvar win:make-backup-files t "*Create a backup of window configuration file or not.") ;;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.") ;;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 '(top left minibuffer ;;cursor-type auto-lower auto-raise cursor-color mouse-color ;;background-color foreground-color ;;menu-bar-lines ;;saving menu-bar-lines doesn't work with x-toolkit line-space vertical-scroll-bars 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 method of auto positioning, 'absolute for this variable puts the new frame by counting 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.") ;;; ---------- 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:sizes (make-vector win:max-configs nil)) (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.") ;; for Emacs-19 (defvar win:use-frame (and (string= "19" (substring emacs-version 0 2)) window-system) "*Non-nil means switch windows with frame.") (and (fboundp 'eval-when-compile) (eval-when-compile (require 'revive))) (if win:switch-map nil (setq win:switch-map (make-sparse-keymap)) (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))) (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-show-window-list) (define-key global-map (concat prefix " ") 'win-toggle-window) (define-key global-map (concat prefix "!") 'win-delete-current-window)))) (define-key win:switch-map "=" 'win-show-window-list) (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-delete-current-window) ) ;; define menu-bar (if (null (fboundp 'make-frame)) nil ;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])))) (mapcar (function (lambda (bind) (define-key win:menu-bar-buffer-map (vector (car bind)) (cdr bind)))) (reverse '((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 (lookup-key global-map [menu-bar file]) [see-you] (cons "See you!(revivable)" 'see-you-again) 'kill-buffer) (define-key-after (lookup-key global-map [menu-bar file]) [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) "Delete Nth entry of window configuration buffer." (if (= n 0) (error "Can't delete window %c" win:base-key)) (if (<= (win:No-of-windows) 1) (error "Can't delete sole window.")) (if (y-or-n-p (format "Erase %sconfiguration of %c{%s}?" (if killbufmsg "buffer and " "") (+ n win:base-key) (aref win:names n))) (progn (aset win:configs n nil) (if win:use-frame (delete-frame nil)) (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: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. " (cond (win:use-frame (win:adjust-window t) (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)))) (or nil ;;nosetwc (or (win:select-frame to) (aset win:configs to nil) (error "Window frame [%c] does not exist." (+ win:base-key to))))) (t (or preserve (win:store-config win:current-config)) (or nosetwc (win:set-wc to)) )) (win:update-mode-line to) (if (/= to win:current-config) (setq win:last-config win:current-config win:current-config to)) (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) (aset win:names win:current-config (buffer-name))) ;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: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)))))) ) ;;;###autoload (defun win-switch-to-window (arg) "Switch window configurations to a buffer specified by keyboard." (interactive "p") (let*((window (- last-command-char win:base-key)) (wc (aref win:configs window))) (cond ;;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)uplicate " (if win:use-frame "" "P)reserve ") "F)indfile B)uff X)M-x N)o:") (+ window win:base-key))) (setq ans (if (interactive-p) (read-char) ?y)) (if (string-match (char-to-string ans) "cdpyfbx") (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) (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))) ((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)) ;;(win:switch-window window t 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)rev R)ecent D)elete K)ill S)ave2buf L)oad-from-buf A)save-As") (let ((c (downcase (read-char)))) (cond ((= c ?n) (win-next-window arg)) ((= c ?p) (win-prev-window arg)) ((= c ?r) (win-recent-window)) ((= 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)) (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:read-config-file () "Read window configuration file from minibuffer." (let ((dir (file-name-directory win:local-config-file))) (setq dir (read-file-name "Configuration file directory: " dir dir)) (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) "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 (downcase (read-char)))) (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) (if win:use-frame (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) (focus-frame frame) (set-mouse-position frame 0 0) (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-show-window-list (wait) "Show the windows' list in the minibuffer. If the list is too long to be displayed in a line, it will be shown line by line waiting WAIT seconds on each line. Default wait is 2 seconds." (interactive "P") (if win:use-frame ;update title (and (win:adjust-window t) (aset win:names win:current-config (buffer-name)) (raise-frame (window-frame (minibuffer-window)))) (aset win:names win:current-config (buffer-name)) (aset win:configs win:current-config (current-window-configuration))) (let ((i 1) (list "")cl ll cw width) (setq width (if win:use-frame (frame-width (window-frame (minibuffer-window))) (screen-width))) (while (< i win:max-configs) (if (aref win:configs i) (progn (setq ll list cw (cond ((= i win:current-config) "*") ((= i win:last-config) "+") (t "")) cl (format "%s%c{%s} " cw (+ i win:base-key) (aref win:names i)) list (concat ll cl)) (if (< (length list) (- width 3)) nil (message (concat ll "...")) (sit-for (if wait (prefix-numeric-value wait) 2)) (setq list cl)))) (setq i (1+ i))) (if (string= list "") (message "No window configuration stored.") (message list))) ) (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)) (newh (screen-height)) (neww (screen-width)) (wc (aref win:configs num))) (win:store-config 0) ;;save current configuration into array[0] (if win:use-frame (win:select-frame num) (set-window-configuration wc))) ) (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) (current-window-configuration))) (aset win:names index (buffer-name)) (aset win:sizes index (list (screen-height) (screen-width))) ) (defvar win:mode-string nil) (defun win:update-mode-line (number) "Update mode line for selected window number NUMBER." (setq win:mode-string (format win:mode-line-format (+ number win:base-key))) (set-buffer-modified-p (buffer-modified-p)) (sit-for 0) ) (defun win:recover-deleted-frames () "Detect frames deleted at initialization, and allocate new one for Windows. Do not call this function." (let ((i 1)) (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)))) (aset win:configs i (win:allocate-frame i)) ))) ;;;###autoload (defun win:startup-with-window () "Start up Emacs with window[1] selected." (if (aref win:configs 1) nil (cond ((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-initial, 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 '(lambda () (if (aref win:configs 1) ;Already resumed by resume-windows (win:recover-deleted-frames) (while (null (visible-frame-list)) (message "Waiting for frames to be shown...") (sit-for (string-to-number "0.1"))) (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:store-config 1) (win:update-mode-line 1) (message "Startup with window [1]") (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$" "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-int (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 (win:frame-parameters (aref win:configs winnum)))))) (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) ;;(goto-char (point-min)) ;;(and (search-forward win:revision-prefix nil t) ;; (goto-char (match-beginning 0)) (kill-line 1)) (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)))) (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 ;;(select-frame (aref win:configs win:current-config)) (win:select-frame win:current-config) (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 (car (cdr (read (current-buffer))))) (kill-buffer confb) (switch-to-buffer curb) (if (/= win:current-config arg) (win:switch-window arg)) (restore-window-configuration config) (win:store-config win:current-config)) ) ;;;###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) (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)) ;;;###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)) (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))) (if win:use-frame (let ((conf (car (cdr (car wconflist)))) (win:current-config win:current-config) win:last-config frame) ;;win:switch-window is the easiest way to resume frames. (win:switch-window (car (car wconflist))) (setq frame (aref win:configs (car (car wconflist)))) (set-frame-width frame (car conf)) (set-frame-height frame (car (cdr conf))) (modify-frame-parameters frame (nth 2 (car wconflist))))) (restore-window-configuration (car (cdr (car wconflist)))) (win:store-config (car (car wconflist))) (setq wconflist (cdr wconflist))) (win:set-wc win:current-config) (win:update-mode-line win:current-config)) (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) (while (null (member goal (visible-frame-list))) (sit-for 0)) (raise-frame goal) (select-frame goal) (if (not (eq (selected-frame) goal)) nil (set-mouse-position goal 0 0) (unfocus-frame) 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 (aref win:configs i)) (setq found t)) (setq i (1+ i))) (if found (1- i))) ) (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 (win:use-frame (if (eq (aref win:configs win:current-config) (selected-frame)) t ;selected frame is current window. (let ((sw (win:selected-window))) (if (not sw) (if noerror nil (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)))))) ) (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 (&optional 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. Optional argument 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)) (if (null (win:frame-window (car flist))) (throw 'found (setq frame (car flist))))) (setq flist (cdr flist)))) frame (make-frame (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 minimum 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))) (* win:new-frame-offset-x (1- minn))) mint (- (cdr (assq 'top (frame-parameters frame))) (* 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)))) win:new-frame-offset-x) top (+ (cdr (assq 'top (frame-parameters (selected-frame)))) win:new-frame-offset-y)))) (list (cons 'left left) (cons 'top top))))))) ) ;;; ;; 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 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 (delq 'hight (delq 'width (delq 'top (delq 'left frame-initial-geometry-arguments)))) frame-initial-geometry-arguments (append (list (assq 'hight (frame-parameters frame)) (assq 'width (frame-parameters frame)) (assq 'top (frame-parameters frame)) (assq 'left (frame-parameters frame))) frame-initial-geometry-arguments)))) ) (provide 'windows) (run-hooks 'win-load-hook) ;; $Log$ ;; 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: