Screens
*******

This chapter describes screen features supported by Epoch, except for the Elisp extensions described in Miscellaneous.

Screen Basics
=============

In this document, the term screen will mean an X window, and window will refer to an editor window to avoid confusion.  In most cases working within a screen will be the same as working in a GNU Emacs session.

Each screen contains its own Emacs window hierarchy.  (This terminology is a little confusing: when GNU Emacs uses the term window this refers to the logical structure in which a buffer is displayed.  The name "window" was already appropriated, so we had to call our ``X windows'' something different; they are therefore called screens.) When a screen is first created, it contains a single window with its mode line covering the entire screen.  The buffer for this window is set to *scratch* unless a different buffer is specified.

Epoch supports two types of screens:  edit screens and minibuffer screens.  There will always be at least one edit screen. If Epoch is operating with non-local minibuffers, then there will always be exactly one minibuffer screen; otherwise, a local minibuffer window will appear at the bottom of each edit screen.  Epoch assumes there is at least one edit window at all times.  A single edit screen and the minibuffer window together act much like normal GNU Emacs.

 -- Variable: epoch::nonlocal-minibuffer
     This variable is set to t if there is a distinct minibuffer screen, nil otherwise.

 -- Variable: epoch::synchronize-minibuffers
     If Epoch is operating with local minibuffers, and this variable is set to t, then the contents of all local minibuffer windows will be synchronized with the contents of the real minibuffer window.  This variable defaults to nil.

At any time there is a single selected screen, analogous to the selected window; this is also called the current screen.  Standard window functions work, but they only apply to the current screen; e.g., one-window-p returns non-nil if there is only one window on the current screen. Buffers are shared among all screens, so any buffer can be accessed in any window, and will show up in the buffer list.  Killing buffers removes them from all windows.  The value of epoch::global-update determines whether Epoch updates non-current screens or not (see Screen Updating).

Epoch adds screens as a new Emacs Lisp primitive type.  Screens are printed as #<screen N>, where N is the screen ID.  This ID is a sequence number attached to a screen when it is created.  It serves primarily as a human convenience.  Any argument to a primitive listed as SCREEN can be either a screen object or a screen ID.  However, when the result of a function is a screen, this means a screen object is returned unless specifically mentioned to do otherwise.  Optional screen arguments default to the current screen unless otherwise specified.

A screen that is displayed is said to be mapped; if it is only displayed as an icon, it is said to be unmapped.  By X Window System conventions, a screen is mapped if and only if its X window is mapped.

 -- Variable: inhibit-initial-screen-mapping
     This variable, when bound and set to t, will inhibit the mapping of the first edit screen when Epoch is starting up.  In this case, the only screen which will be mapped initially will be the minibuffer screen.  If Epoch is run with local minibuffers, then the first edit screen will be mapped regardless.  This variable is not bound by default, but can be set in the user's .emacs file.

There is one significant difference between screens and windows: screens are known to external programs (e.g., the X server).  This means that the GNU Emacs scheme for window activities is not sufficient for screen activities.  In particular, the creation of screens is much more complex than window creation.

 -- Function: epoch::create-screen &optional buffer alist
     Creates a new screen (unmapped), and returns it.  If the BUFFER argument is present, that buffer is attached to the single window originally present in the screen, otherwise the *scratch* buffer is used. The ALIST argument is used to override screen creation defaults. See *create-screen-alist-hook* below.

 -- Function: create-screen &optional buffer alist
     Calls epoch::create-screen but does some additional things.  The alist passed to epoch::create-screen is a copy of ALIST appended with a copy of epoch-mode-alist and two additional properties.  These additional properties are icon-name and title (which here default to BUFFER NAME@SYSTEM NAME).  Also see *create-screen-alist-hook below.

 -- Variable: *create-screen-alist-hook*
     This is a hook variable used by create-screen. Just before the call to epoch::create-screen, each function in the hook is called with the screen property alist create-screen has generated. Each function should return a new version of the alist to be used instead. Normally, the hook function will add or modify some of the entries in the alist. See the code in see Screen Pools for an example.

Screen Properties
=================

Screens have a large number of properties (or attributes) that can differ between screens, and are externally visible (e.g., colors, cursor shape and color, font, size, title, class).  Most of the complexity of screen creation is involved in dealing with these properties.  Epoch deals with default-sets which are collections of X window property types and values.  When a screen is created, a default-set is used to set the various properties of the screen.  For information on default sets see X Window Program Defaults.

In order to allow more variety in screens, Epoch provides more ways of overriding the global X default set. A global variable epoch::screen-properties contains an alist of screen properties. At screen creation time, a copy of the global default-set is made, and entries are overwritten with values from epoch::screen-properties.  After that, the alist given as an argument to create-screen (if any) is used to override any previous values.

The order of determination of the default set for each screen is as follows (in increasing order of precedence):

 1. X program defaults (see X Window Program Defaults).

 2. Values in epoch::screen-properties.

 3. Alist argument to epoch::create-screen.

 4. Mode-specific values using epoch-mode-alist, if create-screen is used for creation.

 5. Alist argument to create-screen.

 -- Variable: epoch::screen-properties
     This variable should contain an alist, the key values being screen property keys. The primitive attempts to bypass bad entries, but if the alist is improperly formed, Epoch may experience bizarre failures.

 -- Variable: epoch-mode-alist
     This variable allows you to associate a set of X defaults with an emacs mode.  The form is a list, each element of which is a form (mode-name . ALIST-OF-DEFAULTS).  Whenever create-screen is called, the mode of the BUFFER argument (or the scratch buffer's mode if BUFFER is nil) is used to look in the alist.

     This feature allows you to set geometry, colors, font, etc by mode. It's useful to allow (for example) 80x60 windows for .c and .h files, but a regular size window for other file types.  See the definition of epoch-mode-alist in epoch.el for some examples.

     Thus you can set up a default mode to epoch upon entry and then override portions of it at the time you call create-screen.

The table below is a list of all screen property keys recognized by the screen creation routines. The defaults listed are the hard-wired defaults, but they may be superceded as described in X Window Program Defaults.  Values listed as flag are false if the value is nil, true for any other value.

As an example, to set screens to have the font 9x15 and the Gumby cursor, the following Elisp code would be used:

     (setq epoch::screen-properties
       (cons '(font . "9x15")
              (cons '(cursor-glyph . 56) epoch::screen-properties)))

Name
     Type, Default, Description

foreground
     String, Black, Screen foreground

background
     String, White, Screen background

cursor-color
     String, Black, Text cursor color

cursor-foreground
     String, White, cursor foreground color

cursor-background
     String, Black, cursor background color

border-color
     String, White, X border color

in-border-width
     Number, 2, Internal border width

ex-border-width
     Number, 1, External border width

title
     String, ``Edit'', Screen title

name
     String, ``epoch'', Screen resource name

class
     String, ``Emacs'', Screen class name

update
     String, false, Flag to indicate non-local screen updating

geometry
     String, 80x24, Geometry specifier. Size units are characters.  Screen must be at least 2 lines high.

cursor-glyph
     Number, 86, X cursor glyph.  Index into the cursor font.

reverse
     Flag, False, Reverse foreground / background

font
     String, ``fixed'', Font name

icon-name
     String, ``'', Name of Icon for Screen

motion
     Flag, nil, t will cause motion-events to be sent to screen, nil will inhibit this.

parent
     X resource, nil; if non-nil, must be an X ``resource id''.  The new screen is created as a child of this resource.  Useful to provide clipping-parents, for example when trying to put screen in a form of some kind.  This option is extremely dangerous and you should not use it if you don't know what you are doing.

initial-state
     Flag, True, Starting state of screen. True means NormalState, false is IconicState.

Controlling Screens
===================

The primitives in this section concern internal manipulations of screens.

 -- Function: epoch::get-screen &optional screen
     Coerces a SCREEN or screen ID argument to the corresponding screen object.

 -- Function: epoch::get-screen-id &optional screen
     Coerces a SCREEN or screen ID to the corresponding screen ID. Returns nil if the screen is deleted.

 -- Function: epoch::screen-p screen
     Returns t if the argument is of type SCREEN, nil otherwise.

 -- Function: epoch::screen-list &optional unmapped
     Returns a list of all mapped screens, except the minibuffer which is never in the list. If the argument UNMAPPED is non-nil then unmapped screens are also included.

 -- Function: epoch::next-screen &optional screen unmapped
     Returns the next screen in the internal ordering.  With no arguments, it is the next screen after the current screen.  A SCREEN argument returns the next screen past the argument.  Unmapped screens are not returned, unless the second argument UNMAPPED is non-nil. The minibuffer screen is never returned.

 -- Function: epoch::prev-screen &optional screen unmapped
     Same as epoch::next-screen except the internal screen list is traversed in the opposite order.

 -- Function: epoch::select-screen &optional screen
     Makes the argument SCREEN the current edit screen.  The default is the next screen, as defined by epoch::next-screen.  The minibuffer screen cannot be selected.  Unmapped screens may be selected, but only explicitly or if only unmapped screens are left.  Epoch attempts to remember what window was last selected in each screen, and selects that one.  The hook *SELECT-SCREEN-HOOK* is run at this time.

     Returns the selected screen, or nil if given a bad argument or if SCREEN has been deleted.

     Note: If a window is selected by select-window, an implicit epoch::select-screen is done to select the screen the window is on.  This insures that the current window is on the current screen whether epoch::select-screen or select-window was used. In fact, this primitive actually works by selecting a window in the new screen.

 -- Variable: *select-screen-hook*
     This hook is run by epoch::select-screen.

 -- Function: epoch::current-screen
     Returns the current edit screen.  The minibuffer screen is never returned.

 -- Function: epoch::minibuf-screen
     Returns the minibuffer screen.  If no distinct minibuffer screen exists, then nil is returned.

 -- Function: epoch::delete-screen &optional screen
     Deletes a screen.  Returns t if successful, nil otherwise. It is an error to delete the sole remaining screen, and Epoch will not allow this.

     If you delete a screen and it is the current screen, it first uses epoch::select-screen to select a new screen.

     BUG: Window managers can delete the last edit screen.  If this happens, Epoch will crash and burn in short order.  Window managers should obey the ICCCM standard and send a delete signal to the client; then Epoch can grab this and terminate gracefully.

Screens and Windows
===================

Epoch supports all of the windowing ability of GNU Emacs on each screen. Every window is on a screen, and can never be moved from that screen. Epoch provides some primitives to help in the interaction between screens and windows.

NOTE: The concept of selected-window under Epoch changes slightly from that of GNU Emacs in that asynchronous events (i.e. Focus events) may cause the selected window to change without any user-originated command to do so.  This will cause problems for Elisp packages which make the assumption that the selected window cannot change in the midst of their processing.

 -- Function: epoch::get-buffer-window buffer
     Searchs for a window displaying BUFFER on all screens.  Returns such a window if successful, nil otherwise.  This is effectively an updated version of the normal primitive get-buffer-window, which searches only the current screen and minibuffer.

     Note: selecting a window also selects the screen it is on.  Remember that the window may be on an unmapped screen.  This function has no wrapper since that would collide with the standard function get-buffer-window.

 -- Function: epoch::screens-of-buffer buffer
     Returns a list of all screens on which BUFFER is displayed in a window.

 -- Function: epoch::screen-of-window &optional window
     Returns the screen that WINDOW is on.  Returns the current screen if WINDOW is nil.

 -- Function: epoch::first-window &optional screen
     Returns the first window in canonical order for SCREEN.  Use next-window to find the other windows in the SCREEN.

 -- Function: epoch::selected-window &optional screen
     Returns the selected window for SCREEN.  This is the window that would be selected if the screen it is on were selected, or equivalently the selected window the last time SCREEN was the current screen.

     Note: There is no wrapper for this function, since that would collide with the standard function selected-window.

Variable sized Fonts
====================

Epoch now specifies the dimensions of Emacs windows in pixels.  The primitives window-height and window-width now calculate character dimensions based on pixel dimensions and the base font for that window.  It is important to realize that only the pixel values are "constant"; character/line values will change based on the presence of any proportional fonts or variable-height lines.

NOTE: The behavior of Epoch with standard GNU Emacs Elisp packages should be as expected if fixed fonts are being used; different behavior may be seen with proportional fonts.

 -- Function: window-pixheight &optional window
     Returns the height of window in pixels.  Defaults to selected window.

 -- Function: window-pixwidth &optional window
     Returns the width of window in pixels.  Defaults to selected window.

 -- Function: window-pixedges &optional window
     Returns a list of edge coordinates of window in pixels.  Defaults to selected window.

 -- Function: window-height &optional window
     Returns the height of window in characters.  Defaults to selected window.

 -- Function: window-width &optional window
     Returns the width of window in characters.  Defaults to selected window.

 -- Function: window-edges &optional window
     Returns a list of the edge coordinates of the window in characters. (LEFT TOP RIGHT BOTTOM).  NOTE: LEFT and TOP will be approximate, according to the base font for the screen; RIGHT will be one more than the rightmost column in the window; and BOTTOM is one more than the bottommost row used by the window and its mode-line.

Epoch now provides pixel-based functions and variables analogous to several character-based functions:

 -- Function: current-pixel
     Returns a pixel position corresponding to current location of point. Does not take window dimensions into consideration; may return pixel values past the right edge of the window.

 -- Function: move-to-pixel pixel
     Moves point to the character position corresponding to pixel position PIXEL.  Ignores values of PIXEL which are past the edge of the window.

 -- Variable: fill-pixel
     Pixel column beyond which automatic line-wrapping should happen. Automatically becomes local when set in any fashion.  If FILL-COLUMN is set to nil, the value of AUTO-FILL-HOOK is called if the current pixel position is past this value.  The value of LINE-FILL-HOOK is called if text insertion will cause the current line to extend past FILL-PIXEL.

 -- Function: text-width string &optional font
     Return the length of text in STRING as displayed using FONT, or the base font of the current screen and window.

Manipulating Screens
====================

These primitives allow control of the windowing system aspects of screens.  Most of them correspond directly to X Window System calls.

Each of these functions return the screen, if successful, or nil otherwise.

The SCREEN-OR-XWIN arguments may be screen objects or X resource object with type window (see X Resources).

 -- Function: epoch::raise-screen &optional screen-or-xwin
     Raises the SCREEN-OR-XWIN to the top of the display.  This is called by epoch::select-screen.

 -- Function: epoch::lower-screen &optional screen-or-xwin
     Lowers the SCREEN-OR-XWIN to the bottom of the display.

 -- Function: epoch::map-screen &optional screen-or-xwin
     Maps the SCREEN-OR-XWIN onto the display.  No effect if the screen is already mapped.

 -- Function: epoch::unmap-screen &optional screen-or-xwin
     Unmaps the SCREEN-OR-XWIN.  This is for sophisticated users only, as it does not check to see if the screen is the edit screen or the minibuffer. If the unmapped screen is the edit screen, it remains so; you just won't be able to see it.

 -- Function: epoch::mapraised-screen &optional screen-or-xwin
     This does a MapRaised call on the SCREEN-OR-XWIN.  This is equivalent to doing a map followed atomically by a raise.  If no argument is present, it uses the current screen.

 -- Function: epoch::iconify-screen &optional screen
     Sends ICCCM client message requesting iconification of screen (or current screen if no argument is present).

     Note:

       * Some window managers are not ICCCM compliant and will not handle this correctly.

       * ICCCM standard says that to uniconify, an epoch::map-screen should be used.  This doesn't seem to work for many window managers at present.

 -- Function: epoch::screen-mapped-p &optional screen
     Returns t if the SCREEN exists and is mapped, nil otherwise.

 -- Function: epoch::screen-height &optional screen
     Returns the height (in characters) of the SCREEN.  NOTE: there is no Epoch wrapper function for this primitive, as it would conflict with the existing GNU Emacs screen-height primitive.  The height returned is calculated according to the base font for that screen.

 -- Function: epoch::screen-width &optional screen
     Returns the width (in characters) of the SCREEN.  NOTE: there is no Epoch wrapper function for this primitive, as it would conflict with the existing GNU Emacs screen-width primitive.  The width returned is calculated according to the base font for that screen.

 -- Function: epoch::change-screen-size &optional width height screen
     Attempts to resize the SCREEN, leaving the upper left corner fixed.  The WIDTH and HEIGHT are in characters, and default to the current width and height.  This uses the XResizeWindow() call, which may be intercepted by the window manager.  The WIDTH and HEIGHT values are adjusted be be not more than 150.  The HEIGHT is adjusted to at least 1 for the minibuffer and 2 for edit screens.

 -- Function: epoch::font &optional font screen
     If called with nil FONT argument, this function returns the current font.  If called with font argument, it changes SCREEN's font to be that font.  It will resize the screen so that it still has the same character geometry.  It operates on the current screen if SCREEN is nil.  The result is a list of three elements: Font name, character-width, character-height in pixels.

 -- Function: epoch::title &optional name screen
     If called with nil NAME argument, this function returns the X screen name for SCREEN or the current screen.  If name is a string, SCREEN's title is changed accordingly.

 -- Function: epoch::icon-name &optional name screen
     If called with nil NAME argument, this function returns the X screen icon name for SCREEN or the current screen.  If name is a string, SCREEN's icon name is changed accordingly.

 -- Function: epoch::plane-size
     Returns a cons pair.  Car is plane width, cdr is plane height in pixels. (A plane is a ``minor screen'' on a display: on mono screens, there is just one plane, color screens sometimes have several).

 -- Function: epoch::screen-information &optional screen-or-xwin
     Returns information about SCREEN-OR-XWIN, or the current screen if SCREEN-OR-XWIN is nil.  The information is a list with the following elements:

      1. X location of screen in pixels

      2. Y location of screen in pixels

      3. Width of screen in pixels

      4. Height of screen in pixels

      5. External Borderwidth in pixels

      6. Internal Borderwidth; for an xwin, this is always 0.

      7. Map state: t if normal, nil if iconic.

 -- Function: epoch::move-screen x y &optional screen-or-xwin
     Sends request to window manager to move upper-left corner of SCREEN-OR-XWIN (or current screen if no third argument) to given (X,Y) coordinates in pixels.  Note that some window managers may choose to ignore this request.

 -- Function: epoch::foreground &optional color screen
     Set/get the foreground color of the screen.  If COLOR is nil then the function returns the current foreground color as an X Resource.  Otherwise it attempts to set the foreground color, and returns t on success and nil otherwise.

 -- Function: epoch::background &optional color screen
     Set/get the background color of the screen.  If COLOR is nil then the function returns the current background color as an X Resource.  Otherwise it attempts to set the background color, and returns t on success and nil otherwise.

 -- Function: epoch::cursor-background &optional color screen
     Set/get the text cursor background color of the screen.  If COLOR is nil then the function returns the current text cursor background color as an X Resource.  Otherwise it attempts to set the text cursor background color, and returns t on success and nil otherwise.

 -- Function: cursor-color &optional color screen
     Same as epoch::cursor-background.

 -- Function: epoch::cursor-foreground &optional color screen
     Set/get the text cursor foreground color of the screen.  If COLOR is nil then the function returns the current text cursor foreground color as an X Resource.  Otherwise, it attempts to set the text cursor foreground color, and returns t on success and t otherwise.

 -- Function: epoch::cursor-glyph &optional glyph screen
     Set/get the X cursor glyph.  If GLYPH is nil, returns the current glyph number, otherwise attempts to set the glyph.

 -- Function: epoch::flash-screen &optional screen-or-xwin
     Flash the SCREEN-OR-XWIN.  If the argument is a screen object, the flashing is done by exchanging the foreground and background colors, pausing .25 seconds, and then exchanging them again.  For an X resource (even if it is an Epoch screen), the flashing is done by inverting the pixels, pausing, and then inverting again.  This is effective on a monochrome display, but is not as effective for color, depending on the foreground and background colors.

Screen Updating
===============

Epoch allows you to control which screens are updated as their contents are changed.  The default is to only update the current screen, which is maximally efficient.  It is possible, however, to set things up so that all screens or only some subset of the screens are updated.  This is useful if you are editing a buffer which is displayed on multiple screens, or if you have a shell or other process running in one buffer and you are working in another.  Then you can set things up so that the screen with the shell continues to update as it runs, while you work in another screen.  There are several ways to do this, all involving the value of the global variable epoch::global-update.

The functions and variables are:

 -- Variable: epoch::global-update
     There are three classes of values for this variable.

       * set to nil.  Disables updating all but the local screen.

       * set to t.  Enables potential updates: particular screens to be updated conditionally based on the value of the screen-local update FLAG.  This flag may be set using epoch::set-update, and is stored in the epoch-mode-alist variable.

       * set to any other value: causes all screens to be updated.  This is a shorthand for setting to t and then setting the update property on each screen individually.

 -- Function: epoch::set-update arg &optional screen
     Sets update flag to ARG for SCREEN, or current screen if nil.  ARG must be t for update, nil for no update. Returns previous value of flag.

 -- Function: epoch::update-p &optional screen
     Returns t if SCREEN's update flag is set, nil otherwise.  Uses current screen if SCREEN argument is not present. This function should be epoch::updatep.

In addition you can use the following primitives to help control when screens get updated:

 -- Function: epoch::redisplay-screen &optional screen
     Forces a non-premptive redraw of argument SCREEN (current screen if nil).

 -- Function: redraw-display
     Clears current screen and redraws what should be there.

 -- Function: recenter &optional line
     Center point in window and redisplay screen.  If LINE is non-nil, put point on that line.  Operates on current window.

 -- Function: epoch::set-screen-modified &optional screen
     Mark the argument SCREEN (current if nil) as modified for update next time Epoch gets around to an update.