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 [Go to Contents] [Search Editorial] Last Modified: Wednesday, 17-Jan-96 06:50:58 PST