VM TOOLBOX Shooting Windows into CMS By John D. Kinne John D. Kinne works for The Computing Center at Miami University in Oxford, Ohio. He is responsible for the installation, maintenance and tuning of CP, CMS, RSCS and other program products. He has been employed in data processing since 1977. He has worked with VM since 1979. I was slow to try out CMS Windows. It got a bad reputation early on, and I guess I may have paid too much attention to that. Recently I've been interested in creating some full-screen tools. CMS Session Services, also known as CMS Windows, provides a few CMS commands that can manipulate a 3270 screen. These CMS commands can be issued from REXX. That means I don't have to resort to Assembly language programming and the CONSOLE macro for my full- screen I/O. Getting the results I wanted from the CMS Session Services commands was not straightforward. I had the command reference and eventually some sample programs. I did not understand what was necessary to put it all together. I had a hard time getting my first window to look the way I wanted it to. I didn't have nearly the trouble with the second. I'm going to try to save you some of that grief. Now that I've got several working windows, I think the facility may play an important role in the future of 3270 communications. As seems to be IBM's habit, they've provided some powerful primitives. Use your IBM documentation for the complete command formats -- I'll try to deal with the concepts. What Are the CMS Session Services? CMS Session Services requires that you play in three courts at the same time. You have a physical screen. This is what you see when you look at your terminal. Most physical screens are 24 lines long by 80 columns wide, but we've all seen a lot of variations. You also have a virtual screen to work with. Your virtual screen contains the text and data that you may eventually view. The virtual screen may be quite a bit larger than the physical screen; it will not necessarily all be displayed at once. A window connects the virtual screen to the physical screen. It is given an area on the physical screen. It must be smaller than the physical screen. You look at your virtual screen through it. Since I had trouble getting this straight, I'll try an analogy. Think about your evening sports news. Perhaps there is a sports anchor talking about some basketball play-off. During the discussion, a replay of tonight's big game is displayed to the right of the anchor's head. Several scenes from the game are displayed in the little box while the anchor continues describing the night's events. Our analogy goes as follows. The physical screen is your television. The virtual screen is the whole arena that the game took place in: anything that the camera could have been aimed at. It's all there on the virtual screen. You don't see the whole arena. You only see what the camera is aimed at. The camera creates a window into the evening's events. The window is the little rectangle showing just a portion of the contents of the arena. Your television screen and the arena are fixed in space. They don't move around. You cannot make them larger or smaller. Once they are built, their dimensions are set. The window can move around on your TV screen. It can be enlarged to fill the screen or shrunk until barely visible. The window can display different portions of the virtual screen; first the camera operator points it at a coach, then it's pointed at the scoreboard. There can be more than one window on the arena: one showing the action on the court, another showing the winning coach, and a third showing the losing bench. So too can we have several windows simultaneously displaying portions of a virtual screen. Unlike your TV, we can manipulate the contents of the virtual screens. Like many analogies, this one quickly breaks down. Look at Figure 1. Here the virtual screen contains some data -- text describing something about a local basketball team. A window is used to display a portion of that text. We have been given CMS commands to manipulate the virtual screens, windows and eventually the physical screen. We can build CMS Windows from wherever we can issue CMS commands. In particular, we can build windows from REXX programs. CMS Session Services and full-screen CMS are two different things. Full-screen CMS uses the session services, as does XEDIT. The Basic Shots Before APARs VM35846 and VM35847, there were 28 window commands. Two of these were SET and QUERY. Most of the rest had a second operand of either VSCREEN or WINDOW. The restructuring APARs made VSCREEN and WINDOW the command name. It also added a new command: PSCREEN. QUERY and SET were left alone. In Figures 2, 3 and 4, I've presented a brief description of the functions of the three new commands. Fortunately, you don't have to master all of these operands to display your first window! We can forget the PSCREEN command altogether for the time being -- after we take a moment to notice that we will eventually get some very nice facility from it. It will be useful when we want to save the current physical screen to a CMS file. I like to have a PF key set up to do this. When my users encounter an error, they press the PF key and I get a look at what they were looking at. To get data displayed in a window on your terminal, you need to: o define a virtual screen; o put data on the virtual screen; o define a window, establishing its size and position on the physical screen; o position the window somewhere on the virtual screen to determine which data are displayed; and o display the window. This can all be done from a REXX program. First Shot Now that we've got the basic philosophy of how to build a screen and a window, let's go for it. Figure 5 is a very simple REXX program that closely follows the outline in the last paragraph. It produces the output displayed in Figure 6. Take a moment to look at it. The rest of this section won't make any sense if you don't. Then we'll tear it apart. The first subroutine defines MYSCREEN with the DEFINE VSCREEN command. Only one screen may have this name at a time. If this were production code, I may used the QUERY VSCREEN command to see if a screen already existed with this name. In addition to naming the screen, the VSCREEN DEFINE command also specifies the number of scrollable lines and columns, the number of reserved lines and characteristics like color, highlighting, programmed symbol set and protection. In Figure 5, I asked that MYSCREEN be given 10 lines by 40 columns. I asked for one reserved line on the bottom and reverse red video! Next, I write some data to MYSCREEN with the VSCREEN WRITE command. I am writing on lines 1 through 4 starting in column 1. Just for kicks, I am writing highlighted and protected. I also write a message to the reserved line. This is handy because reserved lines appear whenever the virtual screen is visible. I am using the reserved line to tell the viewer how to get rid of MYSCREEN. DEFINEWINDOW uses the WINDOW DEFINE command to create a window that is 10 lines by 41 columns. This is one column wider than MYSCREEN. The extra column is used to store an attribute byte. The command also requests that the window be shown on line 7 column 15 of the physical screen. It is the programmer's responsibility to make sure that the entire window fits on the physical screen. I requested that a border be placed around the window. The border is outside the 10 by 40 area -- I don't have to provide for it. If it doesn't fit on the physical screen, then it will just not be displayed; that does not create an error. Again, I can only have one window with a specific name, and if this were production code, I may have used the QUERY WINDOW command to make sure that MYWINDOW didn't already exist. I use the WINDOW SHOW command to position the window on the virtual screen. The numeric operands refer to a position on the virtual screen. Where a camera operator adjusts the center of the picture, I am adjusting the position of the upper left-hand corner of the window. MYSCREEN doesn't move, but I can move MYWINDOW around on top of it. This is the command that establishes a relationship between MYSCREEN and MYWINDOW. Before this, they were independent entities. To display MYSCREEN, I use the VSCREEN WAITREAD command. If I had several windows defined on MYSCREEN, they would all be updated. WAITREAD causes the physical screen to be updated and my REXX programs waits for an attention interrupt. The name of the interrupt key is returned in WAITREAD.1. In this example, I display MYSCREEN until the ENTER key is pressed. Finally CLEANUP deletes MYSCREEN and MYWINDOW. Second Shot In Figure 7, we do something just a little more complicated. We use CMS Windows for a simple BROWSE command. This is not production code. It demonstrates some more of the Session Services. There are a few things I would like to call your attention to. After the INIT routine verifies that the file you want to browse is accessed, it gets the number of records in the file. This is later used when the virtual screen is defined. The virtual screen is defined to be the same number of lines as the file. It is also defined to be one column wider than the logical record length of the file. Depending on the size file you want to browse, you may have just defined an immense virtual screen. Of course, the size screen you can define is limited by your virtual storage size. The window is defined to be just 22 lines long and 76 columns wide. Remember that the window must fit on the physical screen. The whole file is written onto the virtual screen with the VSCREEN GET TESTSCR command. It is displayed a few instructions later by the VSCREEN WAITREAD command. This command is executed in the DO FOREVER loop. I'd like you to notice how easy it is to navigate the file -- this is done in that loop also. Depending on the interrupt key pressed, a command is issued to reposition the window on the virtual screen. It is easy to determine which key is pressed, and the window commands are straightforward also. Notice the SET LOCATION TESTWIN OFF command. If the virtual screen that you are looking at is too large to be displayed in its window, you will get a message in the upper right-hand corner of the window. This unlikely command turns that message off. More to Come When I was a kid, I never got the idea behind basketball. The game just didn't make any sense to me. I'm coaching my kids now. I tell them about picking, boxing out, backcourt defense and stopping the offense before they get into our lane. There's a lot to learn. Most of it needs to be learned right away. I can talk all I want, but the only way the kids really learn is by playing and practicing. Hopefully, the kids will learn quicker with me talking; so I keep gabbing on. To use CMS Session Services, you need to know a lot before you get your first window on the screen. The first basket you shoot looks awfully high. After you get past that first high threshold, I think you'll find the Session Services commands straightforward to use. I haven't had this much fun on the computer since I learned how to write assembler macros. Next month, I am going to continue this topic. This month, I looked at a couple of applications that write data to the virtual screen and display it. Next time, we'll give the user a few fields to update, we'll write some data back to the file system and we'll paint some windows on top of others. Till then, take care. /* Was this article of value to you? If so, please let us know by circling Reader Service No. 00. Figure 5: A REXX Program Using CMS Windows /* Display some data in a CMS Window. */ address COMMAND call defineVScreen call writeVScreen call defineWindow call positionWindow call displayWindow call CleanUp return defineVScreen: /* Define a Virtual Screen. */ 'VSCREEN DEFINE MYSCREEN 10 40 0 1 ( RED REV' /* 10 lines, 40 cols*/ return writeVScreen: /* Write some data to V. Screen. */ line.1='Protect your Castle.' line.2='Don''t let the competition in it.' line.3='Yell "shot" when they shoot,' line.4=' And box them out.' do i=1 to 4 /* write data to scrollable area. */ 'VSCREEN WRITE MYSCREEN' i '1' length(line.i)+1 , /* +1 for attrib*/ '(PROTECT HIGH FIELD' line.i end 'VSCREEN WRITE MYSCREEN -1 1 39 ( RESERVED PROTECT DATA', 'Press ENTER to remove this display.' /* in Reserved area.*/ return defineWindow: /* define window on physical screen*/ 'WINDOW DEFINE MYWINDOW 10 41 7 15 ( POP BORDER' return positionWindow: /* put window on virtual screen. */ 'WINDOW SHOW MYWINDOW ON MYSCREEN 1 1' return displayWindow: /* put window on physical screen. */ do until KeyPressed='ENTER' 'VSCREEN WAITREAD MYSCREEN' /* Display window & wait on user. */ KeyPressed=strip(waitread.1) end return Cleanup: /* delete V. Screen and Window. */ 'VSCREEN DELETE MYSCREEN' 'WINDOW DELETE MYWINDOW' return Figure 6: Data Displayed in a Window Protect your Castle. Don't let the competition in it. Yell "shot" when they shoot, And box them out. Press ENTER to remove this display. Figure 7: A Simple BROWSE Command /* SIMPLE BROWSE COMMAND BROWSE FILENAME FILETYPE FILEMODE */ address COMMAND /* Better Integrity. */ TRACE O arg fileid Call Init /* define screen & window, Get file. */ TheEnd=0 do until TheEnd /* main loop. */ 'VSCREEN WAITREAD TESTSCR' /* Paint screen & wait on user. */ KeyPressed=waitread.1 /* Name of the key that caused interrupt*/ Select when KeyPressed='PFKEY 3' then TheEnd=1 when KeyPressed='PFKEY 7' then 'WINDOW BACKWARD' /* Page up. */ when KeyPressed='PFKEY 8' then 'WINDOW FORWARD' /* Page down.*/ when KeyPressed='PFKEY 10' then 'WINDOW LEFT = 40' /* Shift <-. */ when KeyPressed='PFKEY 11' then 'WINDOW RIGHT = 40'/* Shift ->. */ otherwise nop end /* Select */ end /* do Until */ /* And do it again! */ 'VSCREEN DELETE TESTSCR' /* No point in keeping these. */ 'WINDOW DELETE TESTWIN' exit /* We're outta here. */ error: parse arg msg , rc /* Issue an error message and exit. */ say msg exit rc /* We're outta here. */ GetFile: /* Get the file and write it on the virtual screen*/ 'VSCREEN GET TESTSCR' fileid return Define: /* Delete & then define window & screen.*/ x=quiet( 'WINDOW DELETE TESTWIN' ) x=quiet( 'VSCREEN DELETE TESTSCR' ) 'VSCREEN DEFINE TESTSCR' recs lrecl+1 ' 0 0 ( BLUE REV' 'WINDOW DEFINE TESTWIN 22 76 2 3 ( POP BORDER' 'WINDOW SHOW TESTWIN ON TESTSCR 1 2' 'SET LOCATION TESTWIN OFF' /* Don't want "columns" message. */ return quiet: arg cmd /* Issue a command, no responses to terminal. */ 'SET CMSTYPE HT' /* Quiet mode. */ cmd /* Issue the command. */ cmdrc=rc /* Save the return code. */ 'SET CMSTYPE RT' /* Noisy again. */ return cmdrc /* Tell caller about return code. */ Init: /* Make sure file exists, then define Window */ /* and Screen. */ if fileid='' then call error 'Format of command is: B1 File-Name File-Type' , '[File-Mode]' , 16 if index(fileid,'*')>0 then call error 'Fileid may not contain asteriskes.', 8 fileid=SUBWORD(fileid '*',1,3) /* Add asterisk for file mode. */ 'LISTFILE' fileid '(STACK DATE' if rc^=0 then call error 'LISTFILE ended with non-zero rc ', rc pull . . . . lrecl recs . 'DESBUF' /* If there's more than one. */ Call Define /* Define Window & Screen. */ Call GetFile /* Get the file to browse. */ 'VMFCLEAR' /* Clear the physical screen. */ return /* end of Init */