Open Computing ``Hands-On'': ``PC-Unix Connection'' Column: March 94 Listings
Listing 1: Some simple examples of Wksh programs to give you
an idea what you can do to add a graphical dimension to your
shell programs.
A. A quick Wksh example that creates a box
with three push buttons:
#!/usr/bin/wksh -motif
XtAppInitialize TOPLEVEL xmmessages Xmmessages "$@"
XtSetValues $TOPLEVEL geometry:10x10+0+0
confirm "What?" "echo ok; exit" "echo cancel; exit" "echo help; exit"
XtRealizeWidget $TOPLEVEL
XtMainLoop
B. This example looks more like a beginning
X Window System program. It opens a window with a single Motif
pushbutton and exits when the button is activated:
#!/usr/bin/wksh -motif
XtAppInitialize TOPLEVEL silly Silly
XtCreateManagedWidget Btn btn pushButton $TOPLEVEL labelString:"Press me"
XtAddCallback $Btn activateCallback "exit 0"
XtRealizeWidget $TOPLEVEL
XtMainLoop
Listing 2. A simple in/out board.
#!/usr/bin/wksh -motif
# TO RUN THIS SCRIPT get your window system running. Call this script
# "example.wksh". Set its execute permission with "chmod u+x example.wksh".
# Run it with "example.wksh". Make sure the wksh command is on your
# system and in your shell command search path (PATH).
# This Windowing Korn Shell example is a companion to the March 1994 issue
# of Unix World's Open Computing magazine, the column "The PC Unix
# Connection" column and script written by Tom Yager
# (tyager@maxx.net). Requires the Windowing Korn Shell (wksh) as
# implemented in System V, release 4.2 with standard Motif toolkit
# bindings.
# Copious comments will help explain this simple application. To move
# beyond that, you'll need two books: "Graphical User Interface Programming"
# and "Windowing System API Reference." Both are published by Prentice-Hall.
# You may also find O'Reilly's book on the X Toolkit to be helpful.
# The first line identifies the shell and the user interface style, here Motif.
# First, initialize the toolkit. A convenience call handles the toolkit init
# and creates the needed top level window. This invisible window provides
# a parent for the application's main window.
# Like all calls that create windows, XtAppInitialize loads a wksh variable
# with a value that references the new window.
NUMROWS=5
let NUMCOLS=NUMROWS+1
# XtAppInitialize [arguments...]
XtAppInitialize TOPLEVEL uw_example "Tom Yager's Trivial wksh Demo"
# A wksh interface starts with a main window. This can be any supported
# Motif widget, but it's usually a "container widget." These contain
# (through parentage) and organize smaller widgets. In this example, we
# use a rowColumn widget. XtCreateManagedWidget is another convenience
# function that creates an instance of a widget and sets it up to manage
# itself once you make it visible. You may abbreviate XtCreateManagedWidget
# using the alias "cmw".
# XtCreateManagedWidget [resources...]
XtCreateManagedWidget CONTROLS controls rowColumn $TOPLEVEL \
orientation:horizontal numColumns:$NUMCOLS packing:PACK_COLUMN
# Resources (colon-separated name:value pairs) define a widget's appearance
# and behavior. See the (3Xm) section of the API Reference for each
# widget's resources.
# Remember to strip off the "XmN" prefix shown in the API reference before
# using a resource in a wksh script.
# Set up column labels across the top. Buttons are used for
# aesthetics' sake; clicking on them does nothing.
cmw LABEL1 label1 pushButton $CONTROLS recomputeSize:false \
labelString:"In/Out"
cmw LABEL2 label2 pushButton $CONTROLS recomputeSize:false \
labelString:"Name"
cmw LABEL3 label3 pushButton $CONTROLS recomputeSize:false \
labelString:"Location"
cmw LABEL4 label4 pushButton $CONTROLS recomputeSize:false \
labelString:"Returning"
cmw LABEL5 label5 pushButton $CONTROLS recomputeSize:false \
labelString:"Notes"
# Construct each data row. NUMROWS determines the number of rows this script
# will build. Although this script creates a static number of data rows, you
# can create and destroy widgets dynamically. Consider that your first
# exercise.
# The first element of each row is a pair of checkboxes denoting whether the
# person is in or out. Because the number of columns in the control widget
# are fixed, we must create a single container widget that holds the two
# checkboxes. That container uses just one column. We'll use the
# Exclusives widget. This automatically unselects all other child pushbuttons
# when one is pressed.
INDEX=1
while ((INDEX <= $NUMROWS)); do
# We'll use the XmCreateRadioBox convenience function. This creates a
# rowColumn widget to hold our in/out toggleButtons. It ensures that only
# one of the buttons is selected at a time.
# XmCreateRadioBox [-m] var parent name
XmCreateRadioBox -m CHECKS[INDEX] $CONTROLS checks$INDEX \
orientation:horizontal numColumns:1
cmw CHECK_IN[INDEX] check_in$INDEX toggleButton ${CHECKS[INDEX]} \
labelString:"IN"
cmw CHECK_OUT[INDEX] check_out$INDEX toggleButton ${CHECKS[INDEX]} \
labelString:"OUT"
# Then we add three text fields: name, location and returning (the latter
# for the expected time/date of return).
cmw NAME[INDEX] name$INDEX textField $CONTROLS columns:20
cmw LOCATION[INDEX] location$INDEX textField $CONTROLS \
columns:10
cmw RETURNING[INDEX] returning$INDEX textField $CONTROLS \
columns:10
# Create a pushbutton labeled "Notes...". We'll set this up to pop up a
# floating window containing a multi-line text editor.
cmw NOTES[INDEX] notes$INDEX pushButton $CONTROLS labelString:"Notes..."
# Set up functions to call when in/out checkboxes and the "Notes" buttons
# are pressed. Pass the row of the control to the function as an argument.
# It's considered bad form to refer to a function that we haven't
# defined yet, but the callback expressions aren't evaluated until the
# control is clicked on ("arm"ed). Callback functions appear below.
XtAddCallback ${CHECK_IN[INDEX]} armCallback "cb_check_in $INDEX"
XtAddCallback ${NOTES[INDEX]} armCallback "cb_notes $INDEX"
let INDEX=INDEX+1
done
# Construct the pop-up window. It won't appear until the user clicks on one
# of the "Notes..." buttons. The CreatePopupShell function is used because
# this is a new top-level window that will appear and disappear apart from
# the others.
XtCreatePopupShell NOTES_SHELL Notes_shell dialogShell $TOPLEVEL \
title:"Notes"
sv $NOTES_SHELL height:343 width:294
cw NOTES_FORM Notes_form form $NOTES_SHELL
# Create an editable text window
cmw NOTES_TEXT Notes_text text $NOTES_FORM \
editMode:MULTI_LINE_EDIT rows:20 columns:40
# Create a "Done" button
cw NOTES_DONE Notes_done pushButton $NOTES_FORM \
`under $NOTES_TEXT 10` labelString:"Done"
# pop up the notes text editor--this function def is not executed until it's
# called
cb_notes() {
#Retrieve the contents of the "name" text field for the selected row
#gv is shorthand for XtGetValues
gv ${NAME[$1]} value:TITLE_NAME
# Place the name in the title of the text edit window
# sv is shorthand for XtSetValues
sv $NOTES_SHELL title:"Notes: $TITLE_NAME"
XtRealizeWidget $NOTES_SHELL
XtManageChild $NOTES_DONE
XtManageChild $NOTES_FORM
}
# Mark someone back in by clearing out text fields on that row
cb_check_in() {
for a in ${LOCATION[$1]} ${RETURNING[$1]}; do
sv $a value:""
done
}
# Tell the toolkit to display the main window and its children when we
# kick off the processing loop.
XtRealizeWidget $TOPLEVEL
# Display the widget tree, manage all managed widgets, and watch for user
# input events. This call never exits; you must terminate the application
# from another location. In this case, it's the callback for the "Quit"
# button. You can also force termination by using the system menu (on the
# left side of the title bar)
XtMainLoop
Copyright © 1995 The McGraw-Hill Companies, Inc. All Rights Reserved.
Edited by Becca Thomas / Online Editor / UnixWorld Online /
editor@unixworld.com
Last Modified: Wednesday, 17-Jan-96 06:50:58 PST