FormLib — Form Management Library

Complete functionality for creating and managing application windows in Plan9Basic. Create, show, position, style, and respond to events on forms across all six supported platforms. 105 functions.

CategoryCountDescription
Error Handling4form_error, form_errormsg$, form_strerror$, form_clearerror
Creation & Lifecycle5form# (3 overloads), form_free, form_close
Display7form_show, form_showmodal, form_showex#, form_hide, form_visible (get/set), form_showfullscreenicon (get/set)
Position & Size16left/top/width/height (get/set), bounds#, move#, size#, center#
Constraints6minwidth/minheight/maxwidth/maxheight (get/set), constraints#
Window State & Style14windowstate, maximize#, minimize#, restore#, borderstyle, formstyle, stayontop, fullscreen
Appearance6caption (get/set), fill (get/set), transparency (get/set)
Close Behavior5closeaction (get/set), allowclose (get/set), modalresult (get/set)
Client Area2form_clientwidth, form_clientheight
Padding3padding (get/set), paddings#
Utility7tag (get/set), active, bringtofront#, sendtoback#, setfocus#, invalidate#, handle
Screen Info4form_screenwidth, form_screenheight, form_screenscale, form_screenorientation
Events2612 event types × set/get + clearcallbacks#

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportWin32/Win64
Linux✅ Full SupportGTK-based
Android✅ Full SupportMobile-optimized
ⓘ Note: form_showmodal is only available on desktop platforms (Windows, macOS, Linux). On mobile, use form_showex# with a callback instead.

Error Handling

CodeDescription
0No error
1Invalid or nil form
2Invalid property
3Invalid value
4Form creation failed
5Invalid callback function
FunctionSignatureDescription
form_error()form_error@Last error code (0–5)
form_errormsg$()form_errormsg$@Last error message as string
form_strerror$(code)form_strerror$@nDescription for a given error code
form_clearerror()form_clearerror@Clear the error state
╯ plan9basic
let frm# = form#("Test", 400, 300)
if form_error() <> 0 then
    println "Error: " + form_errormsg$()
endif

Numeric Values Reference

Plan9Basic does not have built-in constants. The tables below document the numeric values accepted by various functions. You can define your own named values for readability:

╯ plan9basic
' Define readable names for numeric values
let POS_SCREEN_CENTER = 4
let BORDER_SIZEABLE = 2
let CLOSE_FREE = 2
let STATE_MAXIMIZED = 2

Position Modes form_position#

ValueDescription
0Use design-time position
4Center on screen
5Center on desktop
6Center on main form

Border Styles form_borderstyle#

ValueDescription
0No border
1Single-line border (non-resizable)
2Standard resizable border
3Tool window style
4Resizable tool window

Form Styles form_formstyle#

ValueDescription
0Normal form
1Stay on top
2Popup window

Close Actions form_closeaction#

ValueDescription
0No action (form stays open)
1Hide the form
2Free/destroy the form
3Minimize the form

Window States form_windowstate#

ValueDescription
0Normal window state
1Minimized to taskbar
2Maximized to fill screen

Form Creation & Lifecycle

FunctionSignatureDescription
form#()form#@Create form with defaults (640×480, centered)
form#(caption$)form#@$Create form with caption
form#(caption$, w, h)form#@$nnCreate form with caption and size
form_free(frm#)form_free@#Destroy form and release all resources
form_close(frm#)form_close@#Close form (triggers OnClose/OnCloseQuery events)
╯ plan9basic
' Default form
let frm# = form#()

' Named form
let frm# = form#("My Application")

' Named form with specific size
let frm# = form#("My Application", 800, 600)

' Cleanup
form_free(frm#)
⚠ Warning: form_free immediately destroys the form and all child controls.

Form Display

FunctionSignatureDescription
form_show(frm#)form_show@#Show form non-modally
form_showmodal(frm#)form_showmodal@#Show modally (desktop only, blocks until closed)
form_showex#(frm#, func$)form_showex#@#$Show with close callback (cross-platform)
form_hide(frm#)form_hide@#Hide form
form_visible(frm#)form_visible@#Get visibility (0 = hidden, 1 = visible)
form_visible#(frm#, n)form_visible#@#nSet visibility (0/1)
form_showfullscreenicon(frm#)form_showfullscreenicon@#Get fullscreen icon visibility (0/1)
form_showfullscreenicon#(frm#, n)form_showfullscreenicon#@#nShow/hide the fullscreen icon (0/1)
╯ plan9basic
' Non-modal (program continues)
form_show(frm#)

' Modal (desktop only — blocks until closed)
form_showmodal(frm#)

' Cross-platform dialog with callback
function OnDialogClosed(sender#, result)
    if result = 1 then
        println "OK clicked"
    else
        println "Cancelled"
    endif
endfunction

form_showex#(dlg#, "OnDialogClosed")
ⓘ Note: form_showex# is the recommended way to show dialogs on all platforms. The callback receives the form pointer and the modal result value.

Position & Size

FunctionSignatureDescription
form_left(frm#)form_left@#Get X position
form_left#(frm#, x)form_left#@#nSet X position
form_top(frm#)form_top@#Get Y position
form_top#(frm#, y)form_top#@#nSet Y position
form_width(frm#)form_width@#Get width
form_width#(frm#, w)form_width#@#nSet width
form_height(frm#)form_height@#Get height
form_height#(frm#, h)form_height#@#nSet height
form_bounds#(frm#, x, y, w, h)form_bounds#@#nnnnSet position and size in one call
form_move#(frm#, x, y)form_move#@#nnSet position only
form_size#(frm#, w, h)form_size#@#nnSet size only
form_center#(frm#)form_center#@#Center form on screen
form_position(frm#)form_position@#Get position mode
form_position#(frm#, n)form_position#@#nSet position mode (see Numeric Values)
╯ plan9basic
form_position#(frm#, 4)            ' Center on screen
form_bounds#(frm#, 100, 100, 800, 600)  ' Exact placement
form_center#(frm#)                   ' Re-center after resize

println "Position: " + str$(form_left(frm#)) + ", " + str$(form_top(frm#))
println "Size: " + str$(form_width(frm#)) + " x " + str$(form_height(frm#))

Size Constraints

FunctionSignatureDescription
form_minwidth(frm#)form_minwidth@#Get minimum width
form_minwidth#(frm#, w)form_minwidth#@#nSet minimum width
form_minheight(frm#)form_minheight@#Get minimum height
form_minheight#(frm#, h)form_minheight#@#nSet minimum height
form_maxwidth(frm#)form_maxwidth@#Get maximum width
form_maxwidth#(frm#, w)form_maxwidth#@#nSet maximum width
form_maxheight(frm#)form_maxheight@#Get maximum height
form_maxheight#(frm#, h)form_maxheight#@#nSet maximum height
form_constraints#(frm#, minW, minH, maxW, maxH)form_constraints#@#nnnnSet all constraints at once
╯ plan9basic
' Prevent the form from being too small or too large
form_constraints#(frm#, 400, 300, 1200, 800)

' Or set individually
form_minwidth#(frm#, 320)
form_minheight#(frm#, 240)

Client Area

The client area is the usable interior of the form, excluding the title bar and borders. Use these to calculate available space for laying out controls.

FunctionSignatureDescription
form_clientwidth(frm#)form_clientwidth@#Width of the client area in pixels
form_clientheight(frm#)form_clientheight@#Height of the client area in pixels
╯ plan9basic
' Layout a control to fill the entire client area
let cw = form_clientwidth(frm#)
let ch = form_clientheight(frm#)
println "Client area: " + str$(cw) + " x " + str$(ch)

Window State & Style

FunctionSignatureDescription
form_windowstate(frm#)form_windowstate@#Get state (0=normal, 1=min, 2=max)
form_windowstate#(frm#, n)form_windowstate#@#nSet window state
form_maximize#(frm#)form_maximize#@#Maximize window
form_minimize#(frm#)form_minimize#@#Minimize to taskbar
form_restore#(frm#)form_restore#@#Restore from minimized/maximized
form_borderstyle(frm#)form_borderstyle@#Get border style
form_borderstyle#(frm#, n)form_borderstyle#@#nSet border style (see Numeric Values)
form_formstyle(frm#)form_formstyle@#Get form style (0=normal, 1=stay on top, 2=popup)
form_formstyle#(frm#, n)form_formstyle#@#nSet form style
form_stayontop(frm#)form_stayontop@#Get stay-on-top state (0/1)
form_stayontop#(frm#, n)form_stayontop#@#nSet stay-on-top (0/1)
form_fullscreen(frm#)form_fullscreen@#Get fullscreen state (0/1)
form_fullscreen#(frm#, n)form_fullscreen#@#nSet fullscreen mode (0/1)
╯ plan9basic
' Create a fixed-size dialog
let dlg# = form#("Settings", 400, 300)
form_borderstyle#(dlg#, 1)   ' Non-resizable
form_position#(dlg#, 4)      ' Centered

' Create a fullscreen kiosk app
let kiosk# = form#("Kiosk", 800, 600)
form_fullscreen#(kiosk#, 1)

Appearance

FunctionSignatureDescription
form_caption$(frm#)form_caption$@#Get form title
form_caption#(frm#, s$)form_caption#@#$Set form title
form_fill$(frm#)form_fill$@#Get background color
form_fill#(frm#, color$)form_fill#@#$Set background color
form_transparency(frm#)form_transparency@#Get transparency (0.0–1.0)
form_transparency#(frm#, value)form_transparency#@#nSet transparency (0.0=opaque, 1.0=invisible)

Color formats accepted by form_fill#:

FormatExampleDescription
Hex RGB#RRGGBB"#FF0000" = red
Hex ARGB#AARRGGBB"#80FF0000" = semi-transparent red
Namedcolor name"red", "blue", "white", etc.
╯ plan9basic
form_caption#(frm#, "My Application v1.0")
form_fill#(frm#, "#F0F0F0")          ' Light gray background
form_transparency#(frm#, 0.1)        ' Slightly transparent

Close Behavior

FunctionSignatureDescription
form_closeaction(frm#)form_closeaction@#Get current close action
form_closeaction#(frm#, n)form_closeaction#@#nSet close action (0=none, 1=hide, 2=free, 3=minimize)
form_allowclose(frm#)form_allowclose@#Get allow-close state (0/1)
form_allowclose#(frm#, n)form_allowclose#@#nAllow or prevent closing (0/1)
form_modalresult(frm#)form_modalresult@#Get modal result
form_modalresult#(frm#, n)form_modalresult#@#nSet modal result (used with showex#/showmodal)
╯ plan9basic
' Hide instead of destroy when user closes
form_closeaction#(frm#, 1)

' Prevent accidental close
form_allowclose#(frm#, 0)

' Set a result for dialog patterns
form_modalresult#(frm#, 1)  ' OK
form_close(frm#)

Padding

FunctionSignatureDescription
form_padding(frm#)form_padding@#Get uniform padding
form_padding#(frm#, n)form_padding#@#nSet uniform padding on all four sides
form_paddings#(frm#, l, t, r, b)form_paddings#@#nnnnSet individual padding (left, top, right, bottom)
╯ plan9basic
form_padding#(frm#, 10)                ' 10px on all sides
form_paddings#(frm#, 20, 10, 20, 10)  ' 20px left/right, 10px top/bottom

Utility Functions

FunctionSignatureDescription
form_tag(frm#)form_tag@#Get user-defined integer tag
form_tag#(frm#, n)form_tag#@#nSet user-defined integer tag
form_active(frm#)form_active@#Is the form currently active/focused? (0/1)
form_bringtofront#(frm#)form_bringtofront#@#Bring form to the front of the Z-order
form_sendtoback#(frm#)form_sendtoback#@#Send form behind other windows
form_setfocus#(frm#)form_setfocus#@#Set focus to the form
form_invalidate#(frm#)form_invalidate#@#Force form to repaint
form_handle(frm#)form_handle@#Get the native OS window handle (advanced)
ⓘ Note: form_tag is a general-purpose integer you can attach to any form. Useful for identifying forms in shared callback functions.

Screen Information

FunctionSignatureDescription
form_screenwidth()form_screenwidth@Screen width in pixels
form_screenheight()form_screenheight@Screen height in pixels
form_screenscale()form_screenscale@Display scale factor (1.0 = standard, 2.0 = Retina/HiDPI)
form_screenorientation()form_screenorientation@Screen orientation (0 = portrait, 1 = landscape)
╯ plan9basic
println "Screen: " + str$(form_screenwidth()) + " x " + str$(form_screenheight())
println "Scale: " + str$(form_screenscale())
println "Orientation: " + str$(form_screenorientation())

' Size form to half the screen
let frm# = form#("Half Screen")
form_size#(frm#, form_screenwidth() / 2, form_screenheight() / 2)
form_center#(frm#)

Events

Each event has a setter (form_onXXX#(frm#, func$)) and a getter (form_onXXX$(frm#)) to assign or read the callback name. Use form_clearcallbacks#(frm#) to disconnect all callbacks at once.

Event SetterGetterCallback Signature
form_onshow#(frm#, func$)form_onshow$(frm#)function name(sender#)
form_onhide#(frm#, func$)form_onhide$(frm#)function name(sender#)
form_onclose#(frm#, func$)form_onclose$(frm#)function name(sender#, action)
form_onclosequery#(frm#, func$)form_onclosequery$(frm#)function name(sender#) → return 1 to allow, 0 to prevent
form_onactivate#(frm#, func$)form_onactivate$(frm#)function name(sender#)
form_ondeactivate#(frm#, func$)form_ondeactivate$(frm#)function name(sender#)
form_onresize#(frm#, func$)form_onresize$(frm#)function name(sender#, width, height)
form_onkeydown#(frm#, func$)form_onkeydown$(frm#)function name(sender#, key, keychar$, shift$)
form_onkeyup#(frm#, func$)form_onkeyup$(frm#)function name(sender#, key, keychar$, shift$)
form_onpaint#(frm#, func$)form_onpaint$(frm#)function name(sender#)
form_onfocuschanged#(frm#, func$)form_onfocuschanged$(frm#)function name(sender#)
form_clearcallbacks#(frm#)Disconnect all event callbacks
╯ plan9basic
' Keyboard handler
function OnKeyDown(sender#, key, keychar$, shift$)
    println "Key pressed: " + str$(key) + " char: " + keychar$
    if key = 27 then
        form_close(sender#)    ' ESC to close
    endif
endfunction

form_onkeydown#(frm#, "OnKeyDown")
╯ plan9basic
' Close query — ask before closing
function CanClose(sender#)
    ' Return 1 to allow, 0 to cancel
    println "Close requested..."
    return 1
endfunction

form_onclosequery#(frm#, "CanClose")
╯ plan9basic
' Resize handler — update layout dynamically
function OnResize(sender#, w, h)
    form_caption#(sender#, "Size: " + str$(w) + " x " + str$(h))
endfunction

form_onresize#(frm#, "OnResize")

Complete Examples

Simple Application Window

╯ simple_app.bas
' Basic event-driven window
let frm# = form#("Hello World", 400, 300)
form_position#(frm#, 4)
form_fill#(frm#, "#F0F0F0")
form_show(frm#)

' Main loop — keeps the application running
while form_visible(frm#) = 1
    processmessages()
end while

form_free(frm#)

Event-Driven with Keyboard

╯ keyboard_app.bas
function OnKeyDown(sender#, key, keychar$, shift$)
    if key = 27 then
        form_close(sender#)
    endif
endfunction

function OnClose(sender#, action)
    println "Goodbye!"
    return 2
endfunction

let frm# = form#("Press ESC to close", 400, 300)
form_position#(frm#, 4)
form_onkeydown#(frm#, "OnKeyDown")
form_onclose#(frm#, "OnClose")
form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Resizable with Constraints

╯ resizable.bas
function OnResize(sender#, w, h)
    form_caption#(sender#, "Size: " + str$(w) + " x " + str$(h))
endfunction

let frm# = form#("Resize Me", 600, 400)
form_position#(frm#, 4)
form_constraints#(frm#, 400, 300, 1200, 800)
form_onresize#(frm#, "OnResize")
form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Dialog with Buttons

╯ dialog.bas
let dlg# = Pointer#(0)

function OnOK(sender#)
    form_modalresult#(dlg#, 1)
    form_close(dlg#)
endfunction

function OnCancel(sender#)
    form_modalresult#(dlg#, 2)
    form_close(dlg#)
endfunction

function OnDialogClose(sender#, result)
    if result = 1 then
        println "OK clicked"
    else
        println "Cancelled"
    endif
endfunction

dlg# = form#("Confirm", 300, 150)
form_position#(dlg#, 4)

let btnOK# = button#(dlg#, "OK", 50, 100, 80, 30)
let btnCancel# = button#(dlg#, "Cancel", 170, 100, 80, 30)

button_onclick#(btnOK#, "OnOK")
button_onclick#(btnCancel#, "OnCancel")

form_showex#(dlg#, "OnDialogClose")

Adaptive Layout

╯ adaptive.bas
function OnResize(sender#, w, h) local cw, ch
    cw = form_clientwidth(sender#)
    ch = form_clientheight(sender#)
    ' Center a label in the client area
    label_move#(lbl#, cw / 2 - 50, ch / 2 - 10)
endfunction

let frm# = form#("Adaptive", 640, 480)
let lbl# = label#(frm#, "Centered!", 0, 0)
form_onresize#(frm#, "OnResize")
form_position#(frm#, 4)
form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Best Practices

PracticeWhy
Always form_free when doneReleases memory and native OS resources
Use form_showex# instead of form_showmodalWorks on all platforms including mobile
Check form_error() after creationCatches creation failures early
Set form_position#(frm#, 4)Centers on screen — better than guessing coordinates
Use form_constraints#Prevents forms from becoming too small to use
Use a while form_visible = 1 main loopIdiomatic way to keep an event-driven app running
Initialize pointer variables with Pointer#(0)Required before assigning in callbacks or conditional code
Use form_tag to identify formsLets shared callbacks distinguish between multiple forms

Quick Reference

FunctionSignatureDescription
form_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
form#() / form#(s$) / form#(s$,n,n)form#@, form#@$, form#@$nnCreate form (3 overloads)
form_free / form_closeform_free@#, form_close@#Destroy / close form
form_show / showmodal / showex# / hidevariousDisplay control (4)
form_visible / visible#form_visible@#, form_visible#@#nVisibility get/set
form_left/top/width/height (get/set)variousPosition & size (8)
form_bounds# / move# / size# / center#variousBatch position/size (4)
form_position / position#form_position@#, form_position#@#nPosition mode
form_constraints# / min/max width/heightvariousSize constraints (9)
form_clientwidth / clientheightvariousClient area (2)
form_windowstate / maximize# / minimize# / restore#variousWindow state (5)
form_borderstyle / formstyle / stayontop / fullscreenvariousWindow style (8)
form_caption$ / caption# / fill$ / fill# / transparencyvariousAppearance (6)
form_closeaction / allowclose / modalresultvariousClose behavior (6)
form_padding / padding# / paddings#variousPadding (3)
form_tag / active / bringtofront# / sendtoback# / setfocus# / invalidate# / handlevariousUtility (8)
form_screenwidth / screenheight / screenscale / screenorientationvariousScreen info (4)
form_onshow/onhide/onclose/onclosequery/onactivate/ondeactivate/onresize/onkeydown/onkeyup/onpaint/onfocuschangedvariousEvents (set+get) + clearcallbacks (25)
form_showfullscreenicon (get/set)variousFullscreen icon (2)

105 functions. Part of the Plan9Basic GUI library system.