Newer
Older
windows-el / windows.el
@yuuji yuuji on 27 Sep 1994 57 KB Full support for Emacs-19.
;;; -*- 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: