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.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 <-> 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: [{bitmap,pixmap}] -> image
Image holding the pixels currently shown by the frame.
frame <-keyboard_focus: -> window
Window currently designated to receive keyboard input.
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.