1.63 class frame

A frame is a top-level window in the desktop environment. It hosts a collection of window instances and mediates between them and the OS window manager: it carries the title, decorations, geometry, modality and close/save handlers.

The frame's interior is tiled: the member windows together cover the entire client area without overlap. Layout is managed by a tile object associated with the frame.

Every window needs a frame before it can be opened. For simple applications the user does not need to deal with frames explicitly — opening a single window creates a frame as a side-effect. Windows delegate messages they don't understand to their associated frame.

Subclasses of frame are common in user-defined applications that need to coordinate several sub-windows. The set of windows and their spatial relationships may be changed after the frame has been opened.

The underlying driver is SDL3 across all platforms; legacy X11 behaviour and window-manager protocol names (WM_DELETE_WINDOW, WM_SAVE_YOURSELF, ...) are preserved as identifiers but no longer imply X-specific semantics.

See also
- window->initialise
- display<-frames
- topic Window Layout
- class tile
- class window

1.63.1 Class variables

frame.background: colour|pixmap = @_dialog_bg
Default background of the frame. Inherited by windows that do not set an explicit background.
frame.busy_cursor: cursor* = watch (Unix/macOS) / win_wait (Windows)
Cursor used by frame->busy_cursor when the call site does not pass a cursor.
frame.confirm_done: bool =
@off Initial value of frame<-confirm_done: whether frame->wm_delete should pop up a confirmation dialog.
frame.keep_alive: bool =
@off Initial value of frame<-keep_alive: whether the frame keeps the application alive while it is visible.
frame.geometry: name* =
@nil When set, determines the default size and position used by frame->create/frame->open. When @nil, the size is determined by the contained windows and the position by the OS.
See also
frame->geometry
frame.can_resize: bool =
@on Initial value of frame<->can_resize.
frame.horizontal_resize_cursor: cursor = ew_resize
Cursor shown over a horizontal subwindow boundary that can be dragged to resize the adjacent tiles.
frame.vertical_resize_cursor: cursor = ns_resize
Same as the horizontal variant for vertical boundaries.
frame.fit_after_append: bool =
@off Automatically run frame->fit after each frame->append. Convenient while interactively assembling a frame; usually left @off in production code which builds the layout up-front and then calls frame->fit (or frame->open) once.
frame.decorate_transient: bool =
@on If @on, transient frames are still given OS decorations (title, border). Set to @off to obtain bare transient windows.

1.63.2 Instance variables

frame <-> name: name
Name of the frame. Used by application<-member to find frames in an application. Defaults to object<-class_name.

See also frame<->label.

frame <- label: name
Title shown by the OS in the frame's title bar.
frame <- application: application*
Application this frame belongs to. Combining frames into an application lets the application find them by name and define modal relations between them. See frame->modal.
frame <-> display: display
Display (monitor) hosting the frame. Defaults to @display. Changing it after frame->create is not allowed.
frame <- background: colour|pixmap
Background of the frame's client area.
frame <- area: area
Client-area rectangle (the frame without title-bar and borders) in display coordinates. Reflects the current state regardless of what last updated it.

See also frame->set, frame<-bounding_box and frame->geometry.

See also
- frame->set
- frame<-size
frame-geometry: name*
Pending geometry specification used by frame->create to position the frame. Filled by frame->initialise from the frame.geometry class variable, or by frame->geometry. Class frame itself does not provide a default; subclasses commonly do so end users can override the position in ~/.xpce/Defaults.

See library(persistent_frame) for a frame subclass that persists its geometry and sub-window layout.

For the syntax see frame->geometry.

See also
- frame->create
- frame->geometry
frame <- placed: bool
@on once the OS has positioned the frame. Used internally to distinguish an as-yet-unpositioned frame from one whose position has been chosen.
frame-members: chain
Chain of member windows. Holds plain windows and windows wrapped in a window_decorator. The getter frame<-members returns the chain of undecorated windows.
frame <- kind: {toplevel,transient,popup}
What this frame is from the desktop's point of view:

frame <- transient_for: frame*
Frame for which this frame is a transient (e.g. its parent toplevel). Only meaningful when frame<-kind is transient.
See also
- frame<-transients
- frame->transient_for
frame <- transients: chain*
Back-pointer chain holding the frames that are transients of this frame. Maintained by frame->transient_for and frame->unlink. Used to propagate state changes (mapped/exposed/hidden) to the transients.
See also
- frame<-transient_for
- frame->transient_for
frame <- modal: {application,transient}*
A modal frame must be completed before its context can be used again. By default (@nil) the user may operate on any frame. transient blocks just the frame in frame<-transient_for; application blocks every frame in the same frame<-application.

Typical pattern:

display_for(Owner, Result) :-
        new(D, dialog('Enter information')),
        send(D, transient_for, Owner),
        send(D, modal, transient),
        <fill the dialog>
        get(D, confirm_centered,
            Owner?area?center, Return),
        send(D, destroy),
        Return \== @nil.

See also frame<-confirm, frame->transient_for and class application.

frame <- status: {unlinking,unmapped,hidden,iconic,window,full_screen}
Current visibility of the frame:

frame <-> can_delete: bool
When @off, the frame refuses an OS close request (e.g. clicking the close button). Defaults to @on.
See also
- frame->wm_delete
- frame->wm_protocol
frame <-> can_resize: bool
When @on (default) the OS allows the user to resize the frame. Set to @off before frame->create to lock the size.
frame <-> confirm_done: bool
When @on, a confirmation dialog pops up before honouring an OS close request (see frame->wm_delete).

Defaults to the value of the confirm_done class variable (off).

See also
- frame->wm_delete
- frame->wm_protocol
- frame<-can_delete
frame <- input_focus: bool
@on while the frame holds keyboard focus in the OS.

On change to @on the frame sends window->input_focus to frame<-keyboard_focus (or to the window under the pointer). On change to @off the window that currently owns input focus is sent window->input_focus.

See also
- frame->keyboard_focus
- frame->input_window
frame -> keep_alive: bool
When @on, the application must not end while this frame is visible. An application main loop such as Epilog's ep_main/0 halts once display_manager->has_visible_frames fails, so tools, demos and other windows that answer @off do not keep Prolog running.

Defaults to the value of the keep_alive class variable (off). The get method returns the slot; subclasses refine it. E.g., pane_frame answers @on if one of its panes does, where an Epilog terminal always does and a PceEmacs view does while its buffer holds unsaved changes to a file.

See also
display_manager->has_visible_frames
frame <-> sensitive: bool
When @off the frame ignores all user input. Used internally by frame->busy_cursor when block_input is @on.
frame-return_value: unchecked
Holds the value passed to frame->return until frame<-confirm picks it up.
See also
- frame->return
- frame<-confirm
frame <- wm_protocols: sheet
Sheet mapping protocol names to code objects, used by the frame->wm_protocol/frame->done_message/frame->save_message family of OS close/save handlers.
See also
- frame->wm_protocol
- frame->delete_wm_protocol

1.63.3 Send methods

frame ->initialise: label=[name], kind=[{toplevel,transient,popup}], display=[display], application=[application]
Create a frame from its label, kind, display and (optional) application. Frames are often created implicitly as a side-effect of creating a window.

Defaults:

label		untitled
kind		toplevel
display	@display
frame ->unlink:
Destroy the frame and all its member windows. Transients are sent object->free.
frame ->reset:
Cancel any active frame->busy_cursor and restore the normal cursor.
frame ->convert_old_slot: slot=name, value=any
Backward-compatibility hook used when loading saved frames: translates the legacy show slot into frame<-status.
frame ->initialise_new_slot: var=variable
Initialise newly-introduced slots (currently background) when loading older saved instances.
frame ->display: display
React to a display change (e.g. when the host moves the frame to another monitor). Applications normally do not call this.
frame ->append: subwindow=window
Append a window to the frame. Typical when assembling a frame from several sub-windows:
:- pce_begin_class(mail, frame, "Simple mail tool").

initialise(M) :->
        "Create mail tool"::
        send(M, send_super, initialise, mail),
        /* append the various parts to the tool */
        send(M, append, new(B, browser)),
        send(M, append, new(V, view)),
        send(M, append, new(D, dialog)),
        /* specify the layout of the parts in the tool */
        send(V, below, B),
        send(D, below, V),
        ...
See also
- topic Window Layout
- window->above
frame ->delete: member=window
Remove a window from the frame. See also frame->append, window->left, window->above, ...
frame ->fit:
Recompute the layout of the sub-windows and resize the frame to fit the tiled result. Internally:

frame ->resize:
Recompute the layout of the sub-windows in response to the OS resizing the frame.
frame ->update_tile_adjusters: [tile]
Walk the frame<-tile hierarchy and create a tile_adjuster object for each tile whose frame<-can_resize is @on; free adjusters of non-resizable tiles. Called from frame->create.
frame ->set: x=[int], y=[int], width=[int], height=[int], display=[display]
Modify the client area (without title-bar/borders). Window system constraints may clamp the actual values.

When the frame is already shown, the request is sent asynchronously to the OS; the slots are updated when the OS confirms. A successful size change triggers frame->resize.

See also
- frame->size
- frame->position
- frame->geometry
frame ->size: size=size
Equivalent to frame->set.
frame ->width: width=int
frame ->height: height=int
frame ->x: x=int
frame ->y: y=int
Convenience wrappers around frame->set that change one axis.
frame ->position: position=point
Set the top-left position of the frame. Equivalent to frame->set with the point's x and y.
frame ->move: position=point
Alias for frame->position.
frame ->center: center=[point], display=[display]
Move the frame so the given point becomes its centre. Requires the frame to be already created.
frame ->area: area
frame->set from the four fields of the argument area.
frame ->geometry: geometry=name, display=[display]
Parse the geometry specification and apply it (immediately if the frame is open, otherwise stored for frame->create). The syntax is
<width>x<height>[+-]<X>[+-]<Y>[@<monitor>]

All five components are optional. A negative X / Y is measured from the right / bottom edge of the screen. Example:

400x200+0-0

means a 400x200 frame anchored at the bottom-left. The size applies to the client area; the position to the frame including borders.

The @<monitor> suffix, where <monitor> is a value from display_manager<-members, picks the monitor used as the origin. This syntax follows the FVWM convention. If the display argument is given explicitly, @<monitor> is ignored.

See also
- frame->set
- frame.geometry
frame ->create:
Realise the frame in the window system:

  1. Succeed immediately if already created.
  2. Open frame<-display if needed.
  3. Append the frame to display<-frames.
  4. frame->fit to lay out sub-windows.
  5. Create the OS window.
  6. frame->create each member window.
  7. Update cursors.
  8. Set the transient-for relationship (if any).
  9. Apply -geometry if set. 10. frame->update_tile_adjusters.
    See also
    - frame->open
    - display<-frames
    - frame->fit
frame ->uncreate:
Destroy the OS counterpart, leaving the xpce object intact for later reuse.
frame ->open: position=[point], display=[display], grab=[bool]
Open the frame at the given position:

  1. frame->create if not yet created.
  2. frame->set the position if supplied.
  3. frame->status. If grab is @on the frame grabs the pointer (see window->grab_pointer).
    See also
    - frame->open_centered
    - frame->set
    - frame->create
    - window->open
frame ->open_centered: center=[point|frame], display=[display], grab=[bool]
Like frame->open but centres the frame on the given point (or the centre of frame<-display if omitted).
frame ->show: show=bool
Show (@on) or hide (@off) the frame on the display. When a frame becomes shown its transients are shown too. See also frame->open and frame->status.
frame ->mapped: bool
Called when the OS reports the frame mapped (@on) or unmapped (@off). Triggers frame->show on transients to follow the main frame.
frame ->wait:
Dispatch events until the frame has been mapped and its windows have processed at least one redraw request. Used to force the frame visible during a long computation. See also frame->flush and frame->synchronise.
frame ->status: {unmapped,hidden,iconic,window,full_screen,open}
Set the frame's visibility status (see frame<-status). open is a synonym for window.
frame ->closed: open=bool
Compatibility shortcut: frame->closed opens the frame (frame->status), frame->closed iconifies it.
See also
- frame<-closed
- frame->status
frame ->expose:
Raise the frame to the top of the window stack. Internally calls frame->closed (in case the frame was iconic) and then asks SDL to raise the OS window. On success frame->exposed is invoked via the resulting OS event.
See also
- frame<-postscript
- frame->closed
frame ->exposed:
Invoked when the OS reports the frame raised. Sends frame->expose to each transient frame.
See also
- frame->hidden
- frame<-transients
frame ->hidden:
Invoked when the OS reports the frame hidden (lowered or minimised). Sends frame->hide to each transient frame.
See also
- frame->exposed
- frame->transient_for
frame ->label: label=name
Set the title shown in the frame's decorations. Whether and how the label appears is up to the OS theme.
frame ->bell: volume=[int]
Ring the bell on the display hosting the frame.
See also
- display.volume
- display->bell
frame ->busy_cursor: cursor=[cursor]*, block_input=[bool]
Show a temporary cursor (default frame.busy_cursor) on every sub-window of the frame. When block_input is @on, all pointer and keyboard events are blocked while the cursor is active. frame->busy_cursor restores the normal cursor and re-enables input.
See also
display->busy_cursor
frame ->cursor: [cursor]
Set the cursor shown over the frame's decoration / background (i.e. when the pointer is on the area between sub-windows). Used by frame->event while resizing tiles.
frame ->input_focus: bool
Receive notification from the window system that this frame has (@on) or has lost (@off) keyboard focus. Forwards to frame<-keyboard_focus or the window currently under the pointer.
frame ->input_window: window
Direct all keyboard events arriving on this frame to the indicated window. Appropriate when only one sub-window contains keyboard-sensitive controls.
frame ->keyboard_focus: [window]*
When set to a window, all keyboard input arriving at any sub-window is redirected there. The argument need not be a member of the frame. @nil/@default makes keyboard input follow the pointer.
frame ->event: event
Handle an event that landed on the frame's background or decoration. Two cases are dispatched:

frame ->post_event: event
Re-dispatch a keyboard event that wasn't consumed elsewhere. Fails by default.
frame ->typed: event|event_id
Distribute a typed key across the frame's sub-windows so any window can accept it as an accelerator.
frame ->return: unchecked
Make a blocking frame<-confirm call on this frame return with the given value. Stores it in -return_value.
See also
- frame<-confirm
- frame-return_value
frame ->report: kind={status,inform,progress,done,warning,error,fatal}, format=[char_array], argument=any ...
Redefinition of visual->report that walks a frame's report chain:

  1. Call visual<-report_to; if it returns a value other than frame<-display, forward frame->report there.
  2. Try frame->report on each frame<-members window until one succeeds. Windows by default delegate back to their frame, so the loop detects and breaks this cycle.
  3. If the frame is transient, forward to frame<-transient_for.
  4. Fall back to visual->report.
frame ->wm_protocol: protocol=name, action=code
Register a handler for an OS protocol message. The name is matched against incoming protocol events; on a match the code is executed with @receiver set to the frame and @arg1 to its first window.

Historically these names matched X11's WM_PROTOCOLS messages, notably WM_DELETE_WINDOW (close request) and WM_SAVE_YOURSELF (session save). On SDL3 only the close-request path remains; the others are accepted but never triggered.

See also
- frame<-wm_protocols
- frame->save_message
- frame->done_message
- frame->delete_wm_protocol
frame ->delete_wm_protocol: protocol=name
Remove a protocol handler installed with frame->wm_protocol.
frame ->done_message: action=code
Shortcut for frame->wm_protocol. Default: message(@receiver, wm_delete).
See also
- frame->wm_delete
- frame->wm_protocol
frame ->save_message: action=code
Shortcut for frame->wm_protocol. Kept for completeness; SDL3 does not emit this event.
frame ->wm_delete:
Default action for an OS close request:

  1. Fail if frame<-can_delete is @off.
  2. If frame<-confirm_done is @on, pop up display->confirm. Fail if the user cancels.
  3. visual->destroy the frame. @see frame->done_message @see frame<-can_delete @see frame<-confirm_done
frame ->show_label: show=bool
Compatibility alias: @on is equivalent to frame->kind, @off to frame->kind. New code should use frame->kind.
frame ->transient_for: frame*
Declare this frame as a transient (e.g. dialog or inspector) for the argument frame. Effects:

frame ->attach_transient: frame
frame ->detach_transient: frame
Maintain the frame<-transients chain. Called by frame->transient_for and frame->unlink; user code rarely invokes them directly.
frame ->redraw: [area]
Redraw the resize-handle widgets between sub-windows. Used after layout changes.

1.63.4 Get methods

frame <-frame: -> frame
Returns itself. Provided so the same selector resolves on a frame, on its member windows and on the graphicals displayed within.
frame <-contained_in: -> display
Equivalent to frame<-display.
frame <-contains: -> chain
Chain with all member windows; equivalent to frame<-members.
frame <-members: -> chain
New chain holding the (undecorated) member windows.
frame <-member: name -> window
First member window with that name. Looks through the window_decorator wrappers automatically.
frame <-catch_all: window_name=name -> window
Maps <window_name>_member to the corresponding member window:
?- new(@f, frame),
   send(@f, append, new(V, view)),
   send(new(D, dialog), below, V),
   send(V, open).

?- send(@f?view_member, format, 'Hello World\n').
frame <-convert: window -> frame
Convert a window to its containing frame.
frame <-tile: -> tile
Root of the tile hierarchy that lays out this frame.
See also
class tile
frame <-area: -> area
Client-area rectangle of the frame on the display.
frame <-size: -> size
Size of frame<-area.
frame <-position: -> point
Top-left position of frame<-area on the display.
frame <-geometry: -> name
Geometry specification for the current state of the frame, suitable for storing and re-applying via frame->geometry.
frame <-show: -> bool
@on when frame<-status is open; @off otherwise.
frame <-closed: -> bool
@on when the frame is iconified, @off when it is open.
frame <-image: -> image
Image holding the pixels currently shown by the frame.
See also
window<-image for the pixels of a single window.
frame <-keyboard_focus: -> window
Window currently designated to receive keyboard input.
frame <-next_focus: -> frame
The frame that is to be offered the keyboard when this one gives it up, i.e. when it is closed or hidden. This is the most recently used other frame of frame<-application, whose frame<-members are kept in that order by application->first; a frame outside an application falls back on the frames of its frame<-display. Only a frame whose frame<-kind is toplevel and that is currently open qualifies. Fails if there is no such frame.

This answers a question; it does not move the focus. Normally nothing has to: which window is activated when one closes is decided by the window system, which knows its own focus policy -- under X11 that policy may well be "whatever the pointer is now over", and an application that raises a window of its own on top of it is fighting the user. XPCE uses frame<-next_focus only where a platform leaves the question unanswered, which on MacOS it does for the windows SDL creates.

See also
- frame<-keyboard_focus for the window inside a frame.
- application->first, which is what makes the order an order of use.
frame <-confirm: position=[point], display=[display], grab=[bool] -> return_value=any
Open the frame (if not yet opened) and block until frame->return is invoked. Used to implement modal prompts.

When grab is @on the frame grabs the pointer. If the frame is freed while the confirmer is blocking, the call fails.

Typical use:

ask_name(Name) :-
        new(D, dialog('Name Prompter')),
        send(D, append, new(N, text_item(name, ''))),
        send(D, append,
             button(ok, message(D, return, N?selection))),
        send(D, append,
                 button(cancel, message(D, return, @nil))),
        send(D, default_button, ok),
        get(D, confirm, Answer),
        send(D, destroy),
        Answer \== @nil,
        Name = Answer.
See also
- frame->return
- frame-return_value
- frame<-confirm_centered
- window<-confirm
frame <-confirm_centered: center=[point|frame], display=[display], grab=[bool] -> return_value=any
Like frame<-confirm but centres on center (or on the screen if omitted) rather than placing the top-left there.
frame <-open_file: filters=[chain], default=[char_array], allow_many=[bool] -> name|chain
Use the OS file-open dialog to prompt for a file. Arguments:

frame <-save_file: filters=[chain], default=[char_array] -> name
Use the OS file-save dialog. Arguments as for frame<-open_file minus allow_many.