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.
->busy_cursor
when the call site does not pass a cursor.<-confirm_done:
whether frame->wm_delete
should pop up a confirmation dialog.<-keep_alive:
whether the frame keeps the application alive while it is visible.->create/frame->open.
When @nil, the
size is determined by the contained windows and the position by the OS.
<->can_resize.->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.<-member
to find frames in an application. Defaults to object<-class_name.
See also frame<->label.
->modal.->create
is not allowed.See also frame->set, frame<-bounding_box
and frame->geometry.
->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.
window_decorator.
The getter frame<-members
returns the chain of undecorated windows.
toplevel — ordinary application window: title bar,
can be minimised and resized through the OS. Default.
transient — dialog box / inspector window for a
parent
toplevel. Usually decorated but skipped from the task
switcher.
popup — completely invisible to the OS window
manager. Used for tooltips and popup menus. Cannot normally receive
keyboard input; use transient if you need text input.
The kind can only be changed before frame->create.
.g.
its parent toplevel). Only meaningful when frame<-kind
is transient.
->transient_for
and frame->unlink.
Used to propagate state changes (mapped/exposed/hidden) to the
transients.
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.
unmapped — no OS counterpart yet (the frame exists
only as an xpce object).
hidden — OS counterpart exists but is not visible.
Used to stash a frame for later reuse.
iconic — minimised.
window (also written open) — fully
visible. Reached via
frame->open.
full_screen — maximised across the entire screen.
Reach it with send(F, status, full_screen) after frame->create.
See also frame->open, frame<-confirm
and frame->wait. frame->show
and
frame->closed
map to this slot for backward compatibility.
.g.
clicking the close button). Defaults to @on.
->create
to lock the size.->wm_delete).
Defaults to the value of the confirm_done class variable
(off).
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.
->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.
->busy_cursor
when block_input is @on.->return
until frame<-confirm
picks it up.
->wm_protocol/frame->done_message/frame->save_message
family of OS close/save handlers.
Defaults:
label untitled kind toplevel display @display
->free.->busy_cursor
and restore the normal cursor.show slot into frame<-status..g. when the host
moves the frame to another monitor). Applications normally do not call
this.
:- 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),
...
->append,
window->left, window->above,
...
->enforce
on the root tile;
->_compute_desired_size
on each sub-window (currently only dialog implements this);
->enforce
on the root tile;
->set
to the root-tile's ideal width/height. Normally called from frame->create;
user code calls it after runtime layout changes (e.g.
after graphical->size
or after modifying a dialog window).
<-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.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.
->set.->set
that change one axis.->set
with the point's x and y.->position.->set
from the four fields of the argument area.->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.
<-display
if needed.
<-frames.
->fit
to lay out sub-windows.
->create
each member window.
-geometry if set. 10. frame->update_tile_adjusters.
->create
if not yet created.
->set
the position if supplied.
->status.
If grab is @on
the frame grabs the pointer (see
window->grab_pointer).
|frame],
display=[display], grab=[bool]->open
but centres the frame on the given point (or the centre of frame<-display
if omitted).->open
and frame->status.->show
on transients to follow the main frame.->flush
and frame->synchronise.<-status). open
is a synonym for window.->closed
opens the frame (frame->status), frame->closed
iconifies it.
->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.
->expose
to each transient frame.
->hide to each transient 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.
.e.
when the pointer is on the area between sub-windows). Used by frame->event
while resizing tiles.<-keyboard_focus
or the window currently under the pointer.
<-input_focus
window: forward to that window;
.menu_bar_key). If it succeeds the key
is used up; otherwise it goes to the window with the keyboard focus.
Fails by default. Class pane_frame of the IDE uses it to switch tabs
with Control-Page-Up and Control-Page-Down.|event_id<-confirm
call on this frame return with the given value. Stores it in -return_value.
->report
that walks a frame's report chain:
<-report_to;
if it returns a value other than
frame<-display,
forward frame->report
there.
->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.
<-transient_for.
->report.
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.
->wm_protocol.->wm_protocol.
Default: message(@receiver, wm_delete).
->wm_protocol.
Kept for completeness; SDL3 does not emit this event.
<-can_delete
is @off.
<-confirm_done
is @on, pop up
display->confirm.
Fail if the user cancels.
->destroy
the frame. @see frame->done_message
@see frame<-can_delete
@see frame<-confirm_done
->kind,
@off to frame->kind.
New code should use frame->kind..g.
dialog or inspector) for the argument frame. Effects:
type for this frame
and process it as if SDL reported it. This allows testing input that is
not available on the test machine, such as pen and touch input.
type is one of mouse_motion, mouse_button_down,
mouse_button_up, mouse_wheel, pen_proximity_in,
pen_proximity_out, pen_down, pen_up, pen_motion,
pen_button_down, pen_button_up, pen_axis, finger_down,
finger_up, finger_motion, finger_canceled, pinch_begin,
pinch_update, pinch_end, key_down, key_up
and text_input. The attributes of fields are
named after the fields of the SDL event structure (e.g., x, y, which, button, pressure);
missing fields are 0. Positions are relative to the frame, except for
the finger events, whose x and y are
normalised to 0..1 as in SDL. The wheel event takes dx, dy
(precise) and integer_x,
integer_y (whole notches). The key events take key
(the SDL keycode), scancode, mod and repeat,
and text_input takes
char, the code point of the text.<-transients
chain. Called by frame->transient_for
and frame->unlink;
user code rarely invokes them directly.<-display.<-members.window_decorator wrappers automatically.<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').
<-area.<-area
on the display.->geometry.<-status
is open; @off
otherwise.<-image
composites the windows using Cairo instead. The two differ if the
renderer draws differently, e.g., for the sdl_layer
objects of an sdl_window..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.
->return
is invoked. Used to implement modal prompts.
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.
|frame],
display=[display], grab=[bool] -> return_value=any<-confirm
but centres on center (or on the screen if omitted) rather
than placing the top-left there.|chain
filters — chain of tuple objects, each tuple(Name, Extensions)
where Extensions is a ;-separated list or a
chain of char_array. Example:
chain(tuple('Prolog', chain(pl,prolog))).
default — absolute file name used as initial
selection.
allow_many — if @on,
allow multi-select and return a chain of file names; otherwise return a
single name.
<-open_file
minus allow_many.default is the
directory the dialog starts in.