HELP PWMWINDOWS                                 Ben Rubinstein, Jan 1987
                                             Revised: Nic Ford, Mar 1987
                                        Revised: Gareth Palmer, Jul 1989

Basic mechanisms for making and manipulating PWM windows.

Keywords: PWM, window, cursor, label

    pwm_make_txtwin(<string>, <integer:C>, <integer:R>) -> <window-id|false>

    pwm_make_gfxwin(<string>, <integer:W>, <integer:H>) -> <window-id|false>

    pwm_kill_window(<window-id>)

    pwm_windowtype(<item>) -> <word|false>

    checkpwmwinid(<window-id>) -> <item>

    checkpwmuserwin(<window-id>) -> <item>

    checkpwmsurfid(<window-id>) -> <item>

    pwm_mark_textarea(<window-id>, <boolean>,
                     <integer:L1>, <integer:C1>, <integer:L2>, <integer:C2>)

    pwm_windowlocation(<window-id>) -> <vector|false>
    <vector> -> pwm_windowlocation(<window-id>)

    pwm_iconlocation(<window-id>) -> <vector|false>
    <vector> -> pwm_iconlocation(<window-id>)

    pwm_winexternalsize(<window-id>) -> <vector|false>
    <vector> -> pwm_winexternalsize(<window-id>)

    <vector> -> pwm_wininternalsize(<window-id>)
    pwm_wininternalsize(<window-id>) -> <vector|false>

    pwm_move_window(<window-id>)

    pwm_resize_window(<window-id>)

    pwm_expose_window(<window-id>)

    pwm_hide_window(<window-id>)

    pwm_close_window(<window-id>)

    pwm_open_window(<window-id>)

    pwm_refresh_window(<window-id>)

    pwm_winopenstate(<window-id>) -> <word|false>

    <string> -> pwm_windowlabel(<window-id>)
    pwm_windowlabel(<window-id>) -> <string>

    <string> -> pwm_iconlabel(<window-id>)
    pwm_iconlabel(<window-id>) -> <string>

    pwm_windowheight(<window-id>) -> <integer>

    pwm_windowwidth(<window-id>) -> <integer>

    pwm_windowiconic(<window-id> -> <boolean>

    <cursor-id> -> pwm_windowcursor(<window-id>)

    checkpwmcursid(<cursor-id>) -> <item>

    pwm_scan_windows(<list|false:S>, <procedure>)

    pwmnxtwin -> <window-id>

== CONTENTS - (Use <ENTER> g to access required sections) ==

 -- Windows under the PWM
 -- Making, killing, and recognising windows
 -- Selecting a window for text
 -- Finding and changing the size and location of a window
 -- Opening, closing, exposing and hiding a window
 -- Presetting the position and iconic-state of a window
 -- Accessing stored information about a window
 -- Mouse cursors
 -- pwm_scan_windows

-- Windows under the PWM ----------------------------------------------

The Poplog Window Manager allows the user four different types of
window. Firstly there is the "base window", which is used by the top
level interactive Poplog system. Secondly there are "ved windows", which
are dedicated to the editing of all ved-type files (including the help
files - if you are connected to a graphics workstation through the PWM
at the moment, then this help file will be in a "ved window"). Thirdly
and fourthly come "text" and "graphics windows" - these are windows
which can be set up and accessed through the PWM by the user.

The PWM allows you to make windows on your workstation's screen, and
then write text to them, receive input from them and draw graphics in
them. Graphics (including the writing of a line of text from an
arbitrary font at any pixel position) can be drawn on, and input can be
read from, any window - however, terminal emulation requires additional
PWM resources, and so only "text", "base" and "ved" windows support
this.

-- Making, killing, and recognising windows ---------------------------

Base and ved windows are set up automatically by the system as and when
they are required. The user can create text and graphics windows through
the use of the following PWM procedures:

    pwm_make_txtwin(<string>, <integer:C>, <integer:R>) -> <window-id|false>

Make a text window, with internal area C (columns) by R (rows) in
characters, and label <string>. On systems which allow distinct window
and icon labels (such as Sun PWM, but not HP PWM), <string> may contain
a tab character (`\t`) to split it into two strings, the first being
used as the label for the open window, the second as the label for the
iconic window; otherwise the same string will be used for both. Returns
false if there was an error in communication with the PWM, or if the PWM
could not make the window (See HELP *PWMGENERAL - "Communicating with
the PWM").

    pwm_make_gfxwin(<string>, <integer:W>, <integer:H>) -> <window-id|false>

Make a graphics window, with internal area W (width) by H (height) in
pixels, and label <string> as for -pwm_make_txtwin-.  Returns a result as
for -pwm_make_txtwin-.

When you are finished with a window, you should get rid of it to enable
POPLOG and the PWM to reclaim the resources invested in it:

    pwm_kill_window(<window-id>)

This function instructs the PWM to kill the window whose identifier
is in <window-id> and reclaim associated resources.  The window will be
removed from the screen.  It is now an error to apply any of the PWM
functions to the window-id.  The function can only be applied to one of
the user-owned windows.

You can make sure that something is a window, and find out what kind of
window it is, by using the procedure -pwm_windowtype-:

    pwm_windowtype(<item>) -> <word|false>

If the <item> is a PWM window-id (alive or dead), this returns a word
representing the type of the window - one of "base", "ved", "text" or
"gfx".  If it is any other object, this returns false.

There are other procedures - which have rather more drastic results -
which can be used to see if a PWM identifier identifies a valid window:

    checkpwmwinid(<window-id>) -> <item>

This will mishap unless <window-id> is a valid PWM identifier for a
window that has not been killed. The <item> it returns is an integer
which (in current PWMs) is the number the PWM allocated to that window
internally. However, it may be some other item in future PWMs, so it is
probably not a good idea to relie on this, or indeed use the feature.
Just be glad that the system didn't mishap!

    checkpwmuserwin(<window-id>) -> <item>

As -checkpwmwinid-, but <window-id> must be a graphics or text window
owned by the user.

    checkpwmsurfid(<window-id>) -> <item>

As -checkpwmwinid-, but <window-id> must be a valid PWM identifier for a
surface - that is, a window or a page (a page being similar to a
window, except that it is not visible on screen - see HELP
*PWMGRAPHICS).

-- Selecting a window for text ----------------------------------------

All text output by POPLOG when it is connected to the PWM goes to one of
the text windows.  Which one it goes to is controlled by the active
variable (see HELP *ACTIVE_VARIABLES) -pwmtextwindow-. This variable may
be altered by POPLOG or VED, so you should make sure that you know what
it's value is.  For example, the following procedure will write a
character to a window:

    define wincharout(char, win);
        lvars char win;
        dlocal pwmtextwindow = win;
        rawcharout(char);
    enddefine;

You could then use a closure (see HELP *CLOSURES) to create a character
consumer that can be assigned to -cucharout-, to make it the default
channel for printing characters. e.g.

    vars mywin = pwm_maketextwin('listing', 80, 10);

    define myprogram();
        dlocal cucharout = wincharout(% mywin %);
        'this will come out in the window' =>
        ....
        'The database now looks like this' =>
        database ==>
        ....
        etc
        ....
    enddefine;

You should note that the definition of -wincharout- given above used
-rawcharout- instead of -charout-.  This is because, if you are in VED
and have output set to go into some file, -charout- might assign an
appropriate VED window to -pwmtextwindow- when it is called, overriding
the window set by -wincharout-.  So it is best always to use
-rawcharout- when sending text to a specific window.

An aside: the above definition of -wincharout- is not very robust, in
that it assigns to -pwmtextwindow- before checking the arguments.  If it
was called with a string instead of a character, for example, the mishap
message would come out in the window given as argument, which may not be
what was required.  If you made the call by loading a range in VED, it
might be even more confusing, because VED would write the mishap message
into a file, but the display of the message would occur in your window;
then when you came back to VED, the mishap message would be in the file
but you wouldn't see it.  If you can't guarantee that the callers of
-wincharout- would give it the correct arguments, a safer version might
be this:

    define wincharout(char, win);
        lvars char win temp;
        dlocal pwmtextwindow;

        ;;; make sure that -rawcharout- won't crash
        checkinteger(char, 0, 255);

        ;;; make sure it's a reasonable window
        unless (pwm_windowtype(win) ->> temp)
        and member(temp, [text base]) do
            mishap(win, 1, 'TEXT or BASE window needed');
        endunless;

        win -> pwmtextwindow;
        rawcharout(char);
    enddefine;

(Strictly, you could have allowed VED windows to be accepted: but again
this would mess up the display in the VED window, so that what you saw
on screen wouldn't correspond to what VED thought was at that point in
the file; so it is best avoided.)

Text within a window can be highlighted (the method of highlighting, though,
will probably differ from PWM to PWM) by use of the command:

    pwm_mark_textarea(<window-id>, <boolean>,
                     <integer:L1>, <integer:C1>, <integer:L2>, <integer:C2>)

This highlights the portion of <window-id> starting at character cell
(C1,L1) and finishing at (C2,L2). If the <boolean> is true then all
lines within the window from L1 to the line preceding L2 will be
highlighted up to the edge of the window - if false, the highlighting
will only extend to the last non-space character on each line.

-- Finding and changing the size and location of a window -------------

The location of a window is defined as the coordinate of the top-left
corner of the outside of the window, in pixels from the top-left corner
of the usable screen area.  The function -pwm_windowlocation- is used
to access it:

    pwm_windowlocation(<window-id>) -> <vector|false>
    <vector> -> pwm_windowlocation(<window-id>)

The vector in each case is of two integers, representing the x-ordinate
followed by the y-ordinate.  False may be returned when interrogating
the PWM if there is some kind of problem (see "Communications with the
PWM" in HELP *PWMGENERAL).

If the PWM you are using supports icons, you can find or change the
position of the icon for a window with -pwm_iconlocation-, which
follows the same syntax as, and uses analogous arguments to,
-pwm_windowlocation-:

    pwm_iconlocation(<window-id>) -> <vector|false>
    <vector> -> pwm_iconlocation(<window-id>)

There are two potentially useful descriptions of the size of a window:
the external size is the area that the window covers on the screen
(which may be useful in laying out several windows); the internal size
is the area that is available to display text or graphics on.  The
difference between the two may vary between workstations and in some
cases between windows - for example a scroll-bar will increase the
external dimensions of a window without affecting the internal
dimensions.

Thus to discover the size of a window, use one of:

    pwm_winexternalsize(<window-id>) -> <vector|false>
    pwm_wininternalsize(<window-id>) -> <vector|false>

In each case the result is a vector of two integers, respectively width
and height (or false if there was a problem communicating with the PWM).
For the external size the width and height are always measured in
pixels; for the internal size they are in pixels for a graphics window,
but in printable character positions for the base or a text or ved
window.

To set the size of a window, use one of:

    <vector> -> pwm_winexternalsize(<window-id>)
    <vector> -> pwm_wininternalsize(<window-id>)

Again the size is specified by a vector of two integers, representing
width followed by height; and as above, the units are understood to be
pixels except when setting the internal size of a text window, in which
case they are understood to be characters.

When setting the size of a window, the PWM may not use exactly the size
requested: in particular, a request to set the external size of a text
window is always rounded down so that the internal area will accomodate
an exact number of characters, at least one.  Some PWM implementations
may make additional restrictions on the increments in which the size can
be set.  Aside from the minimum restriction that a text window must be
capable of displaying at least one character and the maximum restriction
which may be imposed by the size of the screen, you can assume that an
attempt to set the external size of a window will result in the window
having an external size no greater than requested, while an attempt to
set the internal size will give at least the requested internal area.

You can also instruct the PWM to relocate or resize the window under
user control (through the mouse):

    pwm_move_window(<window-id>)
    pwm_resize_window(<window-id>)

If the window is closed, -pwm_resize_window- has no effect; if the PWM
uses icons, however, -pwm_move_window- will cause the icon to be
relocated.  After one of these functions, you can use one of the
interrogation functions defined above to discover the new size or
location.

-- Opening, closing, exposing and hiding a window ---------------------

A window can be exposed (brought to the front of the screen) by

    pwm_expose_window(<window-id>)

It can be hidden (sent to the back of the screen) by

    pwm_hide_window(<window-id>)

It can be "closed" which, depending on the particular PWM, may mean
becoming an icon or may mean simply dissapearing to be an item on a
menu, by

    pwm_close_window(<window-id>)

It may be opened by

    pwm_open_window(<window-id>)

note that this function always exposes the window.

You can ask the PWM whether a window is open or closed with this
function:

    pwm_winopenstate(<window-id>) -> <word|false>

Like all the functions which interrogate the PWM, this returns false
if it was unable to communicate with the PWM.  Otherwise it returns
either the word "open" or the word "closed".

The PWM can be asked to "refresh" the window by

    pwm_refresh_window(<window-id>)

It is specific to a PWM as to what, if anything, "refreshing" a window
means.  On the Sun PWM, for example, it has no effect on a graphics
window, but on a text window it removes anything drawn on the window by
graphics functions, and removes any text highlighting.

You can examine or change the label displayed in a window's title stripe
with the procedure -pwm_windowlabel-:

    <string> -> pwm_windowlabel(<window-id>)
    pwm_windowlabel(<window-id>) -> <string>

And you can examine or change the label displayed in a window's icon
with the procedure -pwm_iconlabel-:

    <string> -> pwm_iconlabel(<window-id>)
    pwm_iconlabel(<window-id>) -> <string>

On some systems without icons this may mean the string which is
displayed for the window in some menu. On systems which do not
distinguish window and icon labels, it may be the same string as the
title string. Note that the icon will only be able to display a limited
number of characters from its string (on the Suns, for example, the
visible portion of the icon string is only eight characters long)
although this number will differ from PWM to PWM.

Note if you are a LIB * VEDMICE user (see HELP *PWMVED) that this sets
and resets the mouse cursor image when certain buttons are pressed or
released; so if you update -pwm_windowcursor- on a VED window, and then
press a mouse button in it, your cursor assignment may get overridden.
If you specifically want to be to use, e.g., pwmgfxcursor in VED, you
could rewrite your own version of VEDMICE to do this, or to look in some
variable to see what to set the mouse cursor back to when it has
finished.

-- Presetting the position and iconic-state of a window --------------

As seen above, the functions which make windows (-pwm_make_txtwin- and
-pmw_makegfxwin-) only take arguments to describe the title and size of
a window: these have been found to the attributes that most frequently
need to be set before the window is opened.  The PWM puts the window on
screen in the open state, and chooses the position of the window and
icon; after the window has been made you can close it, or change the
position of the window or icon, using the functions described above.

However, for cosmetic or other reasons you may want to pre-set the
position of a window or its icon before it is constructed, or wish it
to be constructed as iconic: these requirements can be achieved through
use of the variable -pwmnxtwin- in place of the window identifier to
any of the functions -pwm_open_window-, -pwm_close_window-,
-pwm_iconlocation- and -pwm_windowlocation- (though in the case of the
latter two functions, this argument is only legal in the updater version
- you cannot find out the position of a window or icon which has not yet
been made.)

Calling one of these functions with -pwmnxtwin- as argument effectively
causes the PWM to make a note of the associated values; when the next
window is made, either by VED or in response to one of the
-pwm_make_XXXwin- functions, it will use the specified values for these
attributes instead of the default ones. By example,

    pwm_close_window(pwmxtwin)

will cause the first window to be built subsequently to be constructed
in its iconic form.

Once a new window has been made (or has failed to be made, i.e. if the
PWM is asked to make a window and for some reason cannot) the 'notes'
are reset, so the next call to make a window will again use the
defaults, unless more calls using -pwmnxtwin- have been made in the
interim.

(Note that the only use of calling -pwm_open_window- with -pwmnxtwin- as
argument is to override a preceeding call of -pwm_close_window-).

-- Accessing stored information about a window ------------------------

Whenever POPLOG recieves a message about the size of a window having
changed, or about a window having been opened or closed, or gives a
command to open, close, or change the internal size of a window, it
stores the information within the window record.  This information
can be accessed much more cheaply than by asking the PWM about the size
of a window or whether it is open or closed: but it is occassionally
inaccurate or out of date (see HELP *PWMINPUT for an explanation).  In
some cases however, especially if the accuracy of the result is not
crucial, or if speed is, it may be useful to access this information.

    pwm_windowheight(<window-id>) -> <integer>

Returns the value that POPLOG has stored for the height (in pixels for a
graphic window, character cells for a text window) of the window given
as argument.

    pwm_windowwidth(<window-id>) -> <integer>

Returns the value that POPLOG has stored for the width (in pixels for a
graphic window, character cells for a text window) of the window given
as argument.

(The accurate alternative to using the above two functions is
-pwm_wininternalsize-, which was described above.)

    pwm_windowiconic(<window-id> -> <boolean>

Returns the value that POPLOG has stored for whether the window is
currently opened or closed: true if the window is believed to closed,
false if it is believed to be open.  Note that this is different from
the return value of the more accurate, PWM-interrogating function
-pwm_winopenstate-, which returns a word "open" or "closed", or false
to indicate that communications with the PWM were unsuccessful.

-- Mouse cursors ------------------------------------------------------

The mouse can move between windows, and a user-definable cursor can
follow it within windows.. There are currently three shapes for the
cursor available, each having its own cursor identifier. The constant
-pwmstdcursor- holds the identifier for the standard cursor,
-pwmgfxcursor- is the identifier for the cursor normally used in
graphics windows, and -pwmtxtcursor- (believe it or not) is the
equivalent identifier for text windows. The PWM procedure

    <cursor-id> -> pwm_windowcursor(<window-id>)

allows you to decide which cursor shape follows the mouse in the window
identified by <window-id>. You can check that a <cursor-id> is valid by
using:

    checkpwmcursid(<cursor-id>) -> <item>

which works in an analogous way to -checkpwmwinid-.

    islivepwmcursor(<cursor-id>) -> <boolean>

Similarly, this will return true if <cursor-id> is the identifier for a
live cursor, false if a dead cursor. If it is not a cursor identifier a
mishap will occur.

At present the facilities for defining your own cursors have not been
added.

-- pwm_scan_windows ----------------------------------------------------

    pwm_scan_windows(<list|false:S>, <procedure>)

This can be used to apply a procedure to all the current PWM windows, or
to some group of them.  The list of "selectors", S consists of any
number of window identifiers and any of the words "base", "ved", "text"
or "gfx".  The procedure will be called on the window-id of each window
whose 'type word' is in the list, unless the window-id itself is in the
list (obviously, therefore, at least one of the type words must be
present in S for the -pwm_scan_windows- invocation to take any action).

For example, this call will close all the VED windows except the current
one:

    pwm_scan_windows([^vedpwmwindow ved], pwm_close_window);

This call will open all windows except the one whose id is -secret-:

    pwm_scan_windows([^secret base ved text gfx], pwm_open_window);

--- C.all/help/pwmwindows ----------------------------------------------
--- Copyright University of Sussex 1987. All rights reserved. ----------
