Commits

viteno  committed 2b3dfb5

Initial import of escreen sources

  • Participants
  • Tags ESCREEN_1_16

Comments (0)

Files changed (5)

+2004-02-28  Jan Rychter  <jan@rychter.com>
+
+	* Created package escreen.
+
+	* escreen.el (escreen-install): added autoload cookie.
+
+# Makefile for Escreen
+
+# This file is part of XEmacs.
+
+# XEmacs 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.
+
+# XEmacs 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 XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# This XEmacs package contains independent single file lisp packages
+
+VERSION = 1.00
+AUTHOR_VERSION = 1.16
+MAINTAINER = Jan Rychter <jan@rychter.com>
+PACKAGE = escreen
+PKG_TYPE = regular
+REQUIRES = xemacs-base
+CATEGORY = standard
+
+ELCS = escreen.elc
+
+STANDARD_DOCS =
+
+include ../../XEmacs.rules
+The escreen package is written by Noah Friedman <friedman@splode.com>.
+
+It has been packaged for XEmacs by Jan Rychter <jan@rychter.com>. Please
+do not send XEmacs-specific bug reports to Noah Friedman.
+
+
+Known problems:
+
+If you use XEmacs 21.5 and launch it with a specified frame size, as I
+do:
+
+(if (eq (console-type) 'x)
+    (set-frame-size (selected-frame) 111 48))
+
+... you might notice that the frame size does not get preserved when
+switching escreens. The following brute-force code provides a temporary
+workaround:
+
+(add-hook 'escreen-goto-screen-hook 
+	  (lambda ()
+	    (if (eql (console-type) 'x)
+		(set-frame-size (selected-frame) 111 48))))
+
+Of course you should replace 111 and 48 by your desired respective X and
+Y sizes.
+
+;;; escreen.el --- emacs window session manager
+
+;;; Copyright (C) 1992, 94, 95, 97, 2001 Noah S. Friedman
+
+;;; Author: Noah Friedman <friedman@splode.com>
+;;; Maintainer: friedman@splode.com
+;;; Keywords: extensions
+;;; Created: 1992-03-23
+
+;;; $Id$
+
+;; 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; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; To install, put this file in your load-path, byte-compile it, and add
+;; the following to your .emacs:
+;;
+;;   (load "escreen")
+;;   (escreen-install)
+
+;; If you are using Emacs 18 or Emacs 19, you may have trouble loading this
+;; program because of the customs syntax officially introduced in Emacs 20.
+;; In that case, first load cust-stub.el, available from
+;;
+;;     http://www.splode.com/~friedman/software/emacs-lisp/
+;;
+;; Updates to escreen.el will also be made available on that page.
+
+;; Inspired by:
+;;   * wicos.el, written by Heikki Suopanki <suopanki@phoenix.oulu.fi>
+;;   * `screen', written by Oliver Laumann, Juergen Weigert,
+;;     and Michael Schroeder.
+
+;; Todo:
+;;   * per-frame screen configurations
+;;   * symbolic names for screens (a la wicos.el)
+;;   * switching active screen from pull-down menu from menubar
+;;   * switching active screen from escreen menu
+;;   * persistance of screens across instances of emacs
+;;     (this may be impossible to do sanely.)
+
+;;; Code:
+
+;; Variable declarations -- can be set by user
+
+(defgroup escreen nil
+  "Window configuration management"
+  :group 'escreen
+  :group 'extensions)
+
+(defcustom escreen-max-screens 10
+  "*Maximum number of screens that may be created."
+  :type 'integer
+  :group 'escreen)
+
+(defcustom escreen-new-screen-default-buffer "*scratch*"
+  "*Default buffer to display in newly-created screens."
+  :type 'string
+  :group 'escreen)
+
+(defcustom escreen-restore-killed-buffers nil
+  "*If non-nil, automatically revisit files if they have been killed.
+That is, if a buffer was killed while in another screen session,
+recreate them, visiting whatever file they were visiting."
+  :type 'boolean
+  :group 'escreen)
+
+(defcustom escreen-preserve-buffer-list-order t
+  "*If non-nil, preserve buffer list for each screen when switching.
+When returning to a previously-saved screen, the buffer list order is
+restored.  Buffers which have been created since the saved screen was last
+visited, are put at the end of the list but the relative order is preserved.
+
+This buffer list order is returned by the function `buffer-list' and
+affects the behavior of `other-buffer', etc.
+
+In Emacs 20 and later, each frame has its own ordered buffer list.
+Switching screen sessions affects the selected frame's buffer list only."
+  :type 'boolean
+  :group 'escreen)
+
+(defcustom escreen-number-mode t
+  "*If non-nil, display current escreen number in mode line."
+  :type 'boolean
+  :group 'escreen)
+
+(defcustom escreen-install-number-mode-format t
+  "*If non-nil, install `escreen-mode-line-format' on `global-mode-string'.
+This is performed by `escreen-install'."
+  :type 'boolean
+  :group 'escreen)
+
+(defcustom escreen-goto-screen-hook nil
+  "*Hook to run after `escreen-goto-screen' completes.
+An example function that can make use of this hook is
+`escreen-enable-number-mode-if-more-than-one-screen'."
+  :type 'hook
+  :group 'escreen)
+
+(defcustom escreen-menu-mode-hook nil
+  "*Hook to run by `escreen-menu' after everything else."
+  :type 'hook
+  :group 'escreen)
+
+
+;; Keybindings
+
+(defcustom escreen-prefix-char "\C-\\"
+  "*Character prefixing escreen commands.
+If you wish to change this, you must also do
+
+   (global-set-key escreen-prefix-char 'escreen-prefix)
+
+to update the prefix in the global keymap."
+  :type 'string
+  :group 'escreen)
+
+(defvar escreen-map nil
+  "*Keymap for escreen commands.")
+(cond
+ ((null escreen-map)
+  (setq escreen-map (make-sparse-keymap))
+  (define-key escreen-map escreen-prefix-char 'escreen-goto-last-screen)
+  (define-key escreen-map "0"    'escreen-goto-screen-0)
+  (define-key escreen-map "1"    'escreen-goto-screen-1)
+  (define-key escreen-map "2"    'escreen-goto-screen-2)
+  (define-key escreen-map "3"    'escreen-goto-screen-3)
+  (define-key escreen-map "4"    'escreen-goto-screen-4)
+  (define-key escreen-map "5"    'escreen-goto-screen-5)
+  (define-key escreen-map "6"    'escreen-goto-screen-6)
+  (define-key escreen-map "7"    'escreen-goto-screen-7)
+  (define-key escreen-map "8"    'escreen-goto-screen-8)
+  (define-key escreen-map "9"    'escreen-goto-screen-9)
+  (define-key escreen-map "?"    'escreen-help)
+  (define-key escreen-map "\C-b" 'escreen-menu)
+  (define-key escreen-map "a"    'escreen-get-active-screen-numbers)
+  (define-key escreen-map "b"    'escreen-get-current-screen-number)
+  (define-key escreen-map "c"    'escreen-create-screen)
+  (define-key escreen-map "g"    'escreen-goto-screen)
+  (define-key escreen-map "k"    'escreen-kill-screen)
+  (define-key escreen-map "n"    'escreen-goto-next-screen)
+  (define-key escreen-map "p"    'escreen-goto-prev-screen)))
+
+(defalias 'escreen-prefix escreen-map)
+
+
+;;; Internal variables.  Do not set these yourself.
+
+;; This should not be modified by the user.  The information it provides is
+;; critical and the calling conventions are different than for
+;; escreen-map-data-format.  The order here is important too.
+;; Do not change this data structure without also changing the
+;; escreen-configuration-data-map-critical-* accessors.
+(defvar escreen-map-critical-data-format
+  (list 'current-buffer
+        (function (lambda () (buffer-name)))
+        'buffer-file-name))
+
+;; If you want to add or change this list, it's best to set
+;; escreen-configuration-alist to nil and run escreen-install afterward.
+;; Otherwise, the new table will be used with old data and may cause errors.
+;;
+;; Note that resetting escreen in this way loses all but the current
+;; window configuration.
+(defvar escreen-map-data-format
+  '((escreen-map-save-window-start    . escreen-map-restore-window-start)
+    (mark-marker                      . escreen-map-restore-mark-marker)
+    (escreen-map-save-point           . escreen-map-restore-point)
+    (escreen-map-save-narrowed-region . escreen-map-restore-narrowed-region)
+    (escreen-map-save-truncate-lines  . escreen-map-restore-truncate-lines)
+    (escreen-map-save-mode-line-face  . escreen-map-restore-mode-line-face)
+    (escreen-map-save-menu-bar-mode   . escreen-map-restore-menu-bar-mode)
+    (buffer-list                      . escreen-map-restore-buffer-list)))
+
+;; Keeps track of escreen state (window config, buffers, etc.)
+;; The structure of each elt is
+;;
+;;  (screen-number #<window-configuration>
+;;                 (((critical-data-buffer-1) user-data-buffer-1 ...)
+;;                  ((critical-data-buffer-2) user-data-buffer-2 ...)
+;;                  ...)
+;;                 selected-window-number)
+;;
+(defvar escreen-configuration-alist nil)
+
+;; Current screen number.  Smallest possible screen number is 0.
+(defvar escreen-current-screen-number 0)
+
+;; Current screen number as a string.
+;; Smallest possible screen number is 0.
+(defvar escreen-current-screen-string
+  (int-to-string escreen-current-screen-number))
+
+;; Last-visited screen number.  Smallest possible screen number is 0.
+(defvar escreen-last-screen-number 0)
+
+;; Highest screen number currently in use.
+(defvar escreen-highest-screen-number-used 0)
+
+;; It's ok to change this, but it makes use of internal variables
+(defvar escreen-mode-line-format
+  '(escreen-number-mode ("S" escreen-current-screen-string " ")))
+
+
+;;;###autoload
+(defun escreen-install ()
+  (interactive)
+  (global-set-key escreen-prefix-char 'escreen-prefix)
+
+  ;; Install screen number on global-mode-string
+  (and escreen-install-number-mode-format
+       (let ((elt '("" escreen-mode-line-format)))
+         (or (escreen-member elt global-mode-string)
+             (setq global-mode-string
+                   (cons elt global-mode-string)))))
+
+  (if escreen-number-mode
+      (escreen-number-mode 1))
+
+  ;; Initialize escreen-configuration-alist by placing current window
+  ;; config in it.
+  (escreen-save-current-screen-configuration))
+
+(defun escreen-number-mode (&optional prefix)
+  "*Toggle escreen-number-mode (see variable docstring).
+If called with a positive prefix argument, always enable.
+If called with a negative prefix argument, always disable.
+If called with no prefix argument, toggle current state."
+  (interactive "P")
+  (setq escreen-number-mode
+        (cond ((null prefix)
+               (not escreen-number-mode))
+              (t
+               (>= (prefix-numeric-value prefix) 0)))))
+
+
+(defun escreen-create-screen ()
+  "Create a new screen and switch to it.
+New screen will display one window with the buffer specified by
+`escreen-new-screen-default-buffer'."
+  (interactive)
+  (let ((new-screen-number (escreen-first-unused-screen-number)))
+    (or new-screen-number
+        (error "escreen: No more screens (see \"escreen-max-screens\")"))
+    ;; Save window configuration before switching to a new one.
+    (escreen-save-current-screen-configuration)
+    (and (> new-screen-number escreen-highest-screen-number-used)
+         (setq escreen-highest-screen-number-used new-screen-number))
+    (setq escreen-last-screen-number escreen-current-screen-number)
+    (setq escreen-current-screen-number new-screen-number)
+    (setq escreen-current-screen-string (int-to-string new-screen-number))
+    (delete-other-windows)
+    (switch-to-buffer escreen-new-screen-default-buffer)
+    ;; Save new window configuration so that it's in the alist.
+    (escreen-save-current-screen-configuration))
+  ;; We run this hook because, in a sense, we have gone to a new
+  ;; screen. but we don't actually call escreen-goto-screen because of the
+  ;; extra setup work here.
+  (run-hooks 'escreen-goto-screen-hook))
+
+(defun escreen-kill-screen (&optional number)
+  "Kill current screen, or screen given by optional argument NUMBER.
+No error occurs if the specified screen number doesn't exist.
+You cannot kill the last existing screen.
+Switch to previous screen if killing active one."
+  (interactive)
+  (let* ((screen-number (or number escreen-current-screen-number))
+         (killing-current-screen-p (eq escreen-current-screen-number
+                                       screen-number))
+         (screen-data (escreen-configuration-escreen screen-number))
+         previous-screen)
+    (cond (screen-data
+           (and killing-current-screen-p
+                (escreen-configuration-one-screen-p)
+                (error "escreen: only one screen, can't kill."))
+           ;; Don't bother looking for previous screen number unless killing
+           ;; current screen, because only then do we need to switch screens.
+           (and killing-current-screen-p
+                (setq previous-screen (escreen-get-prev-screen-number)))
+           (escreen-configuration-escreen-delete screen-data)
+           (and (eq screen-number escreen-highest-screen-number-used)
+                ;; We're killing the screen with the highest number.
+                ;; Look for the next highest number.
+                (setq escreen-highest-screen-number-used
+                      (car (sort (escreen-configuration-screen-numbers) '>))))
+           (and killing-current-screen-p
+                (escreen-goto-screen previous-screen 'dont-update-current))))))
+
+
+(defun escreen-goto-screen (number &optional dont-update-current)
+  "Switch to screen number N.
+Optional arg DONT-UPDATE-CURRENT means don't save the current screen
+configuration, though this isn't intended to be used interactively."
+  (interactive "NGo to escreen number: ")
+  (let ((screen-data (escreen-configuration-escreen number)))
+    (or screen-data
+        (error "escreen: %d: invalid screen number." number))
+    (or dont-update-current
+        (escreen-save-current-screen-configuration))
+    (escreen-restore-screen-map screen-data)
+    (setq escreen-current-screen-string (int-to-string number))
+    (or dont-update-current
+        (setq escreen-last-screen-number escreen-current-screen-number))
+    (setq escreen-current-screen-number number))
+  (run-hooks 'escreen-goto-screen-hook))
+
+(defun escreen-goto-last-screen ()
+  "Switch to the last visited screen."
+  (interactive)
+  (let ((n (if (= escreen-last-screen-number escreen-current-screen-number)
+               (escreen-get-next-screen-number escreen-last-screen-number)
+             escreen-last-screen-number)))
+    (setq escreen-last-screen-number escreen-current-screen-number)
+    (escreen-goto-screen n)))
+
+(defun escreen-goto-prev-screen (&optional n)
+  "Switch to the previous screen.
+This is the nearest lower-numbered existing screen from the current one,
+wrapping around list of screens if necessary.
+If prefix arg N given, jump to the Nth previous screen."
+  (interactive "p")
+  (if (< n 0)
+      (escreen-goto-prev-or-next-screen-internal (- n) 'next)
+    (escreen-goto-prev-or-next-screen-internal n 'prev)))
+
+(defun escreen-goto-next-screen (&optional n)
+  "Switch to the next screen.
+This is the nearest greater-numbered existing screen from the current one,
+wrapping around list of screens if necessary.
+If prefix arg N given, jump to the Nth next screen."
+  (interactive "p")
+  (if (< n 0)
+      (escreen-goto-prev-or-next-screen-internal (- n) 'prev)
+    (escreen-goto-prev-or-next-screen-internal n 'next)))
+
+(defun escreen-goto-prev-or-next-screen-internal (n prev-or-next)
+  (let ((total (length (escreen-get-active-screen-numbers)))
+        (func (if (eq prev-or-next 'next)
+                  'escreen-get-next-screen-number
+                'escreen-get-prev-screen-number))
+        (i 0)
+        (screen-number escreen-current-screen-number))
+    (and (> n total)
+         ;; Trim off excess amount so we do fewer iterations, since
+         ;; wrapping over the total number of screens even once is
+         ;; wasteful and slow.
+         (setq n (- n (* (/ n total) total))))
+    (while (< i n)
+      (setq screen-number (funcall func screen-number)
+            i (1+ i)))
+    (escreen-goto-screen screen-number)))
+
+(defun escreen-goto-screen-0 () (interactive) (escreen-goto-screen 0))
+(defun escreen-goto-screen-1 () (interactive) (escreen-goto-screen 1))
+(defun escreen-goto-screen-2 () (interactive) (escreen-goto-screen 2))
+(defun escreen-goto-screen-3 () (interactive) (escreen-goto-screen 3))
+(defun escreen-goto-screen-4 () (interactive) (escreen-goto-screen 4))
+(defun escreen-goto-screen-5 () (interactive) (escreen-goto-screen 5))
+(defun escreen-goto-screen-6 () (interactive) (escreen-goto-screen 6))
+(defun escreen-goto-screen-7 () (interactive) (escreen-goto-screen 7))
+(defun escreen-goto-screen-8 () (interactive) (escreen-goto-screen 8))
+(defun escreen-goto-screen-9 () (interactive) (escreen-goto-screen 9))
+
+
+(defun escreen-get-current-screen-number ()
+  "Returns the currently selected screen number.
+If called interactively, also print this result in the minibuffer."
+  (interactive)
+  (if (interactive-p)
+      (message "escreen: current screen is number %d"
+               escreen-current-screen-number)
+    escreen-current-screen-number))
+
+(defun escreen-get-active-screen-numbers ()
+  "Print a list of the active screen numbers in the echo area.
+Returns a list of numbers which represent screen numbers presently in use."
+  (interactive)
+  (let ((screen-list (sort (escreen-configuration-screen-numbers) '<))
+        (str "escreen: active screens:"))
+    (and (interactive-p)
+         (progn
+           (mapcar (function (lambda (num)
+                               (setq str (format "%s %d" str num))))
+                   screen-list)
+           (message str)))
+    screen-list))
+
+(defun escreen-help ()
+  "Display a short summary of escreen commands."
+  (interactive)
+  (if (string-lessp emacs-version "19")
+      ;; emacs 18 couldn't list only bindings with a common prefix.
+      (describe-bindings)
+    ;; Emacs 19 can handle escreen-prefix-char (as a string) directly, but
+    ;; for XEmacs, it must be converted to a vector.
+    (describe-bindings (escreen-string-to-vector escreen-prefix-char))))
+
+(defun escreen-string-to-vector (s)
+  (let* ((l (length s))
+         (v (make-vector l nil))
+         (i 0))
+    (while (< i l)
+      (aset v i (aref s i))
+      (setq i (1+ i)))
+    v))
+
+
+;; Return the first unused number available for designation as a screen
+;; number, or nil if  escreen-max-screens  screens are already in use.
+(defun escreen-first-unused-screen-number ()
+  (let ((number 0))
+    (while (and (< number escreen-max-screens)
+                (escreen-configuration-escreen number))
+      (setq number (1+ number)))
+    (and (< number escreen-max-screens) number)))
+
+;; Save window configuration, buffer configuration, and current marks and
+;; point for each displayed buffer for the current screen.
+(defun escreen-save-current-screen-configuration ()
+  (let ((screen-data (escreen-screen-defined))
+        (new-alist-member nil))
+    (if screen-data
+        (setcdr screen-data (escreen-save-screen-map))
+      (setq new-alist-member (cons escreen-current-screen-number
+                                   (escreen-save-screen-map)))
+      (setq escreen-configuration-alist
+            (cons new-alist-member escreen-configuration-alist)))))
+
+;; Return attributes for screen N, or nil if it doesn't exist.
+(defun escreen-screen-defined (&optional n)
+  (escreen-configuration-escreen (or n escreen-current-screen-number)))
+
+;; Return nearest number less than current screen number that is
+;; an active screen, wrapping around end of screen list if necessary.
+(defun escreen-get-prev-screen-number (&optional current-screen-number)
+  (or current-screen-number
+      (setq current-screen-number escreen-current-screen-number))
+  (if (eq 0 escreen-highest-screen-number-used)
+      0
+    ;; Decrement/wrap current screen number
+    (setq current-screen-number (1- current-screen-number))
+    (and (< current-screen-number 0)
+         (setq current-screen-number escreen-highest-screen-number-used))
+    (while (not (assq current-screen-number escreen-configuration-alist))
+      ;; Decrement/wrap current screen number
+      (setq current-screen-number (1- current-screen-number))
+      (and (< current-screen-number 0)
+           (setq current-screen-number escreen-highest-screen-number-used)))
+    current-screen-number))
+
+;; Return nearest number greater than current screen number that is
+;; an active screen, wrapping around end of screen list if necessary.
+(defun escreen-get-next-screen-number (&optional current-screen-number)
+  (or current-screen-number
+      (setq current-screen-number escreen-current-screen-number))
+  (if (eq 0 escreen-highest-screen-number-used)
+      0
+    ;; Increment/wrap current screen number
+    (setq current-screen-number (1+ current-screen-number))
+    (and (> current-screen-number escreen-highest-screen-number-used)
+         (setq current-screen-number 0))
+    (while (not (assq current-screen-number escreen-configuration-alist))
+      ;; Increment/wrap current screen number
+      (setq current-screen-number (1+ current-screen-number))
+      (and (> current-screen-number escreen-highest-screen-number-used)
+           (setq current-screen-number 0)))
+    current-screen-number))
+
+
+;;; Primitive accessors for escreen-configuration-alist
+
+(defun escreen-configuration-escreen (number)
+  (assq number escreen-configuration-alist))
+
+(defun escreen-configuration-escreen-delete (data)
+  (setq escreen-configuration-alist
+        (delq (if (numberp data)
+                  (escreen-configuration-escreen data)
+                data)
+              escreen-configuration-alist)))
+
+(defun escreen-configuration-screen-numbers ()
+  (mapcar 'car escreen-configuration-alist))
+
+(defun escreen-configuration-one-screen-p ()
+  (>= 1 (length escreen-configuration-alist)))
+
+;; Sort the alist so that they are in order numerically.
+(defun escreen-configuration-alist-sort-by-number ()
+  (setq escreen-configuration-alist
+        (sort escreen-configuration-alist
+              (function (lambda (a b)
+                          (< (car a) (car b)))))))
+
+;;; map-data sub-accessors
+
+(defun escreen-configuration-screen-number (l)
+  (nth 0 l))
+
+(defun escreen-configuration-window-data-configuration (l)
+  (nth 1 l))
+
+(defun escreen-configuration-data-map (l)
+  (nth 2 l))
+
+(defun escreen-configuration-selected-window-count (l)
+  (nth 3 l))
+
+;;; screen map data accessors
+
+(defun escreen-configuration-data-map-critical (data)
+  (car data))
+
+(defun escreen-configuration-data-map-user (data)
+  (cdr data))
+
+;;; critical map data accessors
+
+(defun escreen-configuration-data-map-critical-buffer (crit-map)
+  (nth 0 crit-map))
+
+(defun escreen-configuration-data-map-critical-buffer-name (crit-map)
+  (nth 1 crit-map))
+
+(defun escreen-configuration-data-map-critical-buffer-file-name (crit-map)
+  (nth 2 crit-map))
+
+
+(defun escreen-save-screen-map ()
+  (let ((config (current-window-configuration))
+        (win-data nil)
+        (sel-win-count 0)
+        (sel-window (selected-window))
+        (first-window (escreen-first-window))
+        (window nil))
+    (save-excursion
+      (save-window-excursion
+        (select-window first-window)
+        (while (not (eq window first-window))
+          (cond ((null sel-window))
+                ((eq (selected-window) sel-window)
+                 (setq sel-window nil))
+                (t
+                 (setq sel-win-count (1+ sel-win-count))))
+          (setq win-data
+                (cons (cons (escreen-save-critical-data)
+                            (escreen-save-user-data))
+                      win-data))
+          (setq window (select-window (next-window)))
+          (set-buffer (window-buffer (selected-window))))))
+    (list config (nreverse win-data) sel-win-count)))
+
+(defun escreen-restore-screen-map (map)
+  (let ((config (escreen-configuration-window-data-configuration map))
+        (map (escreen-configuration-data-map map))
+        (sel-win-number (escreen-configuration-selected-window-count map))
+        (win-count 0)
+        (sel-win nil))
+    (set-window-configuration config)
+    (select-window (escreen-first-window))
+    (while map
+      (and (= win-count sel-win-number)
+           (setq sel-win (selected-window)))
+      (setq win-count (1+ win-count))
+
+      (escreen-restore-critical-data
+        (escreen-configuration-data-map-critical (car map)))
+      (widen)
+      (escreen-restore-user-data
+        (escreen-configuration-data-map-user (car map)))
+      (select-window (next-window))
+      (setq map (cdr map)))
+    (select-window (or sel-win (escreen-first-window)))))
+
+(defun escreen-save-critical-data ()
+  (mapcar 'funcall escreen-map-critical-data-format))
+
+(defun escreen-restore-critical-data (data)
+  (let ((buffer (escreen-configuration-data-map-critical-buffer data))
+        (buffer-name
+         (escreen-configuration-data-map-critical-buffer-name data))
+        (buf-file-name
+         (escreen-configuration-data-map-critical-buffer-file-name data)))
+    (cond ((escreen-killed-buffer-p buffer)
+           (cond ((null escreen-restore-killed-buffers)
+                  (set-window-buffer (selected-window)
+                                     (get-buffer-create
+                                      escreen-new-screen-default-buffer)))
+                 ((stringp buf-file-name)
+                  (setq buffer (find-file-noselect buf-file-name))
+                  (set-window-buffer (selected-window) buffer)
+                  (or (get-buffer buffer-name)
+                      (rename-buffer buffer-name)))
+                 (t
+                  (set-window-buffer (selected-window)
+                                     (get-buffer-create
+                                      escreen-new-screen-default-buffer)))))
+          (t
+           (set-window-buffer (selected-window) buffer)))))
+
+(defun escreen-save-user-data ()
+  (mapcar (function (lambda (pair) (funcall (car pair))))
+          escreen-map-data-format))
+
+(defun escreen-restore-user-data (data)
+  (let ((funlist escreen-map-data-format))
+    (while (and data funlist)
+      (funcall (cdr (car funlist)) (car data))
+      (setq funlist (cdr funlist))
+      (setq data (cdr data)))))
+
+
+;; Functions used to save and restore screen configuration state.
+;; These are mapped over via presence in escreen-map-data-format.
+
+(defun escreen-map-save-window-start ()
+  (escreen-make-marker (window-start)))
+
+(defun escreen-map-restore-window-start (p)
+  (and (escreen-position-valid-p p)
+       (set-window-start (selected-window) p t)))
+
+(defun escreen-map-restore-mark-marker (mark)
+  (cond ((escreen-position-valid-p mark)
+         (set-marker (or (mark-marker)
+                         ;; when XEmacs zmacs-regions are set, mark-marker
+                         ;; can return nil unless optional arg forcep is
+                         ;; non-nil.
+                         ;; In Emacs transient-mark-mode, mark-marker will
+                         ;; still return a marker, so no magic needed.
+                         (mark-marker t))
+                     (marker-position mark)
+                     (marker-buffer mark)))))
+
+(defun escreen-map-save-point ()
+  ;; If there is a process mark in the current buffer and point is at it,
+  ;; then return the process mark also.  That way, when we return to this
+  ;; screen, point will be at the end of the process output even if that
+  ;; has advanced since then.  Otherwise, just use a before-insertion
+  ;; marker (if supported).
+  (let* ((point-mark (escreen-make-marker (point-marker) nil t))
+         (proc (get-buffer-process (current-buffer)))
+         (proc-mark (and proc (process-mark proc))))
+    (if (and (escreen-position-valid-p proc-mark)
+             (= proc-mark (point)))
+        (cons proc-mark point-mark)
+      point-mark)))
+
+(defun escreen-map-restore-point (pos)
+  (cond ((consp pos)
+         (cond ((escreen-position-valid-p (car pos))
+                (goto-char (car pos)))
+               ((escreen-position-valid-p (cdr pos))
+                (goto-char (cdr pos)))))
+        (t
+         (and (escreen-position-valid-p pos)
+              (goto-char pos)))))
+
+(defun escreen-map-save-narrowed-region ()
+  (cons (and (> (point-min) 1)
+             (escreen-make-marker (point-min)))
+        (and (<= (point-max) (buffer-size))
+             (escreen-make-marker (point-max) nil t))))
+
+(defun escreen-map-restore-narrowed-region (reg)
+  (let ((size (1+ (buffer-size)))
+        (beg (or (car reg) (point-min)))
+        (end (or (cdr reg) (point-max))))
+    (and (escreen-position-valid-p beg)
+         (escreen-position-valid-p end)
+         (<= beg size)
+         (<= end size)
+         (narrow-to-region beg end))))
+
+(defun escreen-map-save-truncate-lines ()
+  truncate-lines)
+
+(defun escreen-map-restore-truncate-lines (v)
+  (setq truncate-lines v))
+
+(defun escreen-map-save-mode-line-face ()
+  (cond ((fboundp 'face-reverse-p)
+         ;; XEmacs mode line face properties
+         (list (face-reverse-p 'modeline)
+               (face-background 'modeline)
+               (face-foreground 'modeline)))
+        ((boundp 'mode-line-inverse-video)
+         mode-line-inverse-video)))
+
+(defun escreen-map-restore-mode-line-face (v)
+  (cond ((fboundp 'face-reverse-p)
+         (set-face-reverse-p 'modeline (nth 0 v))
+         (set-face-background 'modeline (nth 1 v))
+         (set-face-foreground 'modeline (nth 2 v)))
+        ((boundp 'mode-line-inverse-video)
+         (setq mode-line-inverse-video v))))
+
+;; Emacs 19.30 and beyond supports menu bars on ascii terminals, but beware
+;; of turning them off or on once escreen is loaded; if a stored window
+;; configuration was for a frame with a menu bar, but there is no menu bar
+;; presently, that will crash emacs.  This fatal bug is present in all
+;; versions of Emacs prior to 21.0.
+(defun escreen-map-save-menu-bar-mode ()
+  (and (boundp 'menu-bar-mode)
+       menu-bar-mode))
+
+(defun escreen-map-restore-menu-bar-mode (v)
+  (cond ((fboundp 'menu-bar-mode)
+         (if v
+             (menu-bar-mode 1)
+           (menu-bar-mode -1)))))
+
+(defun escreen-map-restore-buffer-list (olist)
+  (and escreen-preserve-buffer-list-order
+       (escreen-set-buffer-list-order olist)))
+
+
+(defun escreen-killed-buffer-p (buffer)
+  (not (if (fboundp 'buffer-live-p)
+           (buffer-live-p buffer)
+         ;; Emacs 18 doesn't have buffer-live-p.
+         ;; Killed buffers have no names.
+         (buffer-name buffer))))
+
+(defun escreen-position-valid-p (pos)
+  (cond ((numberp pos)
+         (<= pos (1+ (buffer-size))))
+        ((markerp pos)
+         (and (eq (marker-buffer pos) (current-buffer))
+              (numberp (marker-position pos))
+              (<= pos (1+ (buffer-size)))))
+        (t nil)))
+
+(defun escreen-set-buffer-list-order (olist)
+  (let (firstbuf buf)
+    (while olist
+      (setq buf (car olist))
+      (and (stringp buf)
+           (setq buf (get-buffer buf)))
+      (cond ((escreen-killed-buffer-p buf))
+            (t
+             (bury-buffer buf)
+             (or firstbuf
+                 (setq firstbuf buf))))
+      (setq olist (cdr olist)))
+    (setq olist (buffer-list))
+    (while (not (eq (car olist) firstbuf))
+      (bury-buffer (car olist))
+      (setq olist (cdr olist)))))
+
+;; Copy existing marker, or make a new one from point.
+;; Emacs 19.30 and later can create markers which are advanced if text is
+;; inserted before them, without needing to call insert-before-markers
+;; explicitly.  This is useful for storing point, mark, etc. since the
+;; buffer may be edited while we are in other escreens.
+(defun escreen-make-marker (pos &optional buffer insertion-type)
+  (let ((new-marker nil))
+    (cond ((markerp pos)
+           (setq new-marker (copy-marker pos))
+           (and buffer
+                (set-marker new-marker (marker-position pos) buffer)))
+          (t
+           (setq new-marker (make-marker))
+           (set-marker new-marker pos buffer)))
+    (and (fboundp 'set-marker-insertion-type)
+         (set-marker-insertion-type new-marker insertion-type))
+    new-marker))
+
+(defun escreen-first-window ()
+  (cond ((fboundp 'frame-highest-window)
+         (funcall 'frame-highest-window))
+        ((fboundp 'frame-first-window)
+         (funcall 'frame-first-window))
+        ((one-window-p)
+         (selected-window))
+        (t
+         (let ((win (selected-window)))
+           (while (not (escreen-first-window-p win))
+             (setq win (next-window win)))
+           win))))
+
+(defun escreen-first-window-p (win)
+  (let ((edges (escreen-window-edges win)))
+    (and (= (nth 0 edges) 0)
+         (= (nth 1 edges) 0))))
+
+
+(defun escreen-menu ()
+  (interactive)
+  (escreen-configuration-alist-sort-by-number)
+  (let ((escreen-menu-buffer (get-buffer-create "*Escreen List*"))
+        alist data-map screen-number)
+    ;; Display buffer now so update of screen cofiguration will be correct.
+    (display-buffer escreen-menu-buffer)
+    ;; Update escreen-configuration-alist to contain up-to-date information
+    ;; on current screen, since we'll be displaying data about it.
+    (escreen-save-current-screen-configuration)
+    (setq alist escreen-configuration-alist)
+    (save-excursion
+      (set-buffer escreen-menu-buffer)
+      (setq buffer-read-only nil)
+      (erase-buffer)
+      (insert " Screen Buffers\n ------ -------\n")
+      (while alist
+        (setq screen-data (car alist))
+        (setq alist (cdr alist))
+
+        (setq screen-number (escreen-configuration-screen-number screen-data))
+        (setq data-map (escreen-configuration-data-map screen-data))
+
+        (if (= screen-number escreen-current-screen-number)
+            (insert (format "*%-6d " screen-number))
+          (insert (format " %-6d " screen-number)))
+        (while data-map
+          (insert (if (> (current-column) 0) "" "        ")
+                  (escreen-configuration-data-map-critical-buffer-name
+                   (escreen-configuration-data-map-critical (car data-map)))
+                  "\n")
+          (setq data-map (cdr data-map)))
+        (insert "\n"))
+      (escreen-menu-mode))))
+
+(defun escreen-menu-mode ()
+  (fundamental-mode)
+  (kill-all-local-variables)
+  (setq buffer-undo-list t)
+  (setq truncate-lines t)
+  (setq buffer-read-only t)
+  (setq major-mode 'escreen-menu-mode)
+  (setq mode-name "Escreen Menu")
+  (run-hooks 'escreen-menu-mode-hook))
+
+
+;; Install this by doing
+;;
+;;    (add-hook 'escreen-goto-screen-hook
+;;              'escreen-enable-number-mode-if-more-than-one-screen)
+;;
+;; By doing so, escreen-number-mode is disabled whenever only a single
+;; escreen is in use.  The only reason for doing this, however, is to save
+;; valuable mode line real estate.
+(defun escreen-enable-number-mode-if-more-than-one-screen ()
+  (if (> (length (escreen-get-active-screen-numbers)) 1)
+      (escreen-number-mode 1)
+    (escreen-number-mode -1))
+  (escreen-force-mode-line-update t))
+
+
+;;; Compatiblity tweaks for Emacs 19, 18, and XEmacs.
+
+(defun escreen-window-edges (&rest args)
+  (apply (if (fboundp 'window-edges)
+             'window-edges
+           ;; For XEmacs 19.13 and later.
+           'window-pixel-edges)
+         args))
+
+(defun escreen-force-mode-line-update (&optional allp)
+  (if (fboundp 'force-mode-line-update)
+      (force-mode-line-update allp)
+    ;; Emacs 18 doesn't have force-mode-line-update
+    (and all (save-excursion (set-buffer (other-buffer))))
+    (set-buffer-modified-p (buffer-modified-p))))
+
+;; Some versions of emacs 18 did not have `member'.
+(defun escreen-member (x y)
+  (if (fboundp 'member)
+      (member x y)
+    (while (and y (not (equal x (car y))))
+      (setq y (cdr y)))
+    y))
+
+(provide 'escreen)
+
+;;; escreen.el ends here

File package-info.in

+(escreen
+  (standards-version 1.1
+   version VERSION
+   author-version AUTHOR_VERSION
+   date DATE
+   build-date BUILD_DATE
+   maintainer MAINTAINER
+   distribution xemacs
+   priority low
+   category CATEGORY
+   dump nil
+   description "Multiple editing sessions withing a single frame (like screen)."
+   filename FILENAME
+   md5sum MD5SUM
+   size SIZE
+   provides (escreen)
+   requires (REQUIRES)
+   type regular
+))