AN INTRODUCTION TO VIEWFRAME Jason Harper 76703.4222@compuserve.com ********************************************************************** This article is reprinted from issue 2.2 (March/April 1995) of PIE Developers magazine. Copyright(C) 1996 by Creative Digital Publishing Inc. All rights reserved. ********************************************************************** The debugging tools available for the Newton platform have been rather limited to date. Here are some of my experiences with the available tools, along with a description of my efforts to improve the situation. THE INSPECTOR The NTK (Newton ToolKit) has a built-in NewtonScript object examination tool called the Inspector. It runs on a host computer (currently, only a Macintosh) tethered to the Newton device being examined. This gives it the distinct advantage over any Newton-based tool of not being limited in its displays to the rather small screen size of current Newton devices. However, it has some major limitations in the information it shows about the objects it displays, and in the options available for further displaying and modifying these objects. As an example, let's look at the output the Inspector might produce when we examine the _proto slot of an unidentified view: #28F {_proto: {#31B}, viewBounds: {#2963E5}, viewJustify: 166, icon: {#4DF}, buttonClickScript: } What is this? From the fact that the frame has both an icon and a buttonClickScript slot, you might deduce that this is a protoPictureButton, or some variation thereof. Looking at the object's prototype might confirm or deny this. To do so, you have to retype the reference number of the _proto slot, in the form ref(0x31b). [According to DTS, Ref is an unreliable function that will be "going away soon." They advise against its use. Ed]. In this case, the prototype contains a debug slot with the value "protoPictureButton" (many of the system proto templates have a debug slot, so you can find out the basic type of many views if you follow their _proto chain far enough). However, it is not always possible to examine frame slots in the Inspector. There are two reasons why your peek might fail: * The reference may no longer be valid. The NewtonScript garbage collector may have reclaimed or relocated the object. The garbage collector can hardly be expected to notice that there is still a reference to the object, on the screen of another computer. * It may be impossible to reenter the reference value. NewtonScript integers are limited to 30 bits, but references are full 32-bit values. If either of the highest two bits of a reference are set, there is no way to directly enter it. You have to use a workaround such as specifying a different path to the desired slot, such as ref(0x28f)._proto in the current example. We've identified the object as a picture button, but what button is it? Looking at its icon might tell, so let's do so: #4DF {mask: , bits: , bounds: {#235F55}} This is, unfortunately, about as far as the Inspector can go. You can look at the bounds slot to find that the icon is 9 by 9 pixels, but the Inspector has no capability for showing any meaningful representation of the mask and bits slots, or any other binary objects that don't have a defined textual version. You can get a little more information by going back to the object's buttonClickScript - typing in ref(0x296405). literals reveals that the script uses the symbols base and Close. Perhaps the script is base:Close()? There's no way to tell for sure. OBJVIEWER It wasn't very long after the Newton introduction that a stand-alone NewtonScript object examining tool appeared - ObjViewer, a freeware program by Robert P. Munafo which was discussed in the last issue of PIE Developers. It has a movable window, half the height of current Newton screens, so you can always see what else is going on. It displays ten lines at a time of frames, arrays, binary objects (shown in hexadecimal) and other data types. Viewing an object referenced by a frame or array slot is as simple as tapping on the line describing it - there is no chance of failure as with the Inspector. For comparison, here is our example frame as displayed by ObjViewer: Frame!0000028F;0/5 slots _proto: {..8..} viewBounds: {..4..} viewJustify: 166 icon: {..3..} buttonClickScript: {..5..}CodeBlock Note that frames are displayed with the number of slots they contain, generally a far more useful piece of data than the reference number shown in the Inspector. The icon object can be viewed more easily than before, and we can even look at its data bits: bits!00235FB6;52 bytes 0: 00000000000401C5| 8: 01C5025E01CE0267|^ g 16: C1800000E3800000| 24: 770000003E000000|w > 32: 1C0000003E000000| > 40: 77000000E3800000|w 48: C1800000 | Unfortunately, this still doesn't tell us what the view actually is, unless you're a lot better at visualizing binary data than I am. A major deficiency of ObjViewer is that it can only examine objects reachable from the root view, as returned by the GetRoot() global function. This is the root of the view system only, not of the entire Newton object system. There are many items of interest that can't be reached from GetRoot(), or that don't exist as objects at all until a program requests them (such as soup entries). Also, ObjViewer is a purely read-only tool. Sometimes it is more convenient to test a small program change directly in the Newton memory rather than taking the time to recompile the whole program. INSPECTOR GADGET Another tool that developers may find useful, which may seem unrelated to object viewing at first glance, is a way to test fragments of NewtonScript code without the time and trouble required to set up a complete program in the NTK. The Inspector can be used for this purpose, although it can be somewhat tricky: some NewtonScript constructs don't work directly from the Inspector - they have to be enclosed in a function which is then called. Also, the Inspector isn't always available. What if you are miles away from your Mac, and are suddenly just dying to know what happens if you remove a slot from a frame you're currently looping through with a foreach statement? Apple supplies a simple NewtonScript experimentation tool named Inspector Gadget. It's one of the sample programs included with the NTK. A variation on this program has been distributed by Howard Oakley under the name NewtonScript Runner. While these tools can be useful (I did a lot of the early work that led to ViewFrame using Inspector Gadget, since I didn't have a Macintosh of my own at the time), they are rather clumsy to use, due to the difficulty of entering NewtonScript expressions directly on a Newton device. Handwritten input is impractical - several important NewtonScript punctuation marks, such as curly and square brackets, are not recognized no matter how clearly you write them. The on-screen keyboard works, but it's constantly asking you if you want to add useless words to your personal dictionary, and it's rather slow to use. Tap in "viewSetupFormScript" a few times, and you know what I mean. But perhaps the main problem with these utilities is their limitation in displaying the results from code you entered. Both just turn the result into a string with the SPrintObject() function, which returns an empty string for many objects. All frames and arrays, as well as some simpler objects such as NIL and TRUE simply come out blank. It's possible to enter a foreach loop that turns frames and arrays into meaningful strings which can be returned, but this routine takes up much of the input area provided by these tools, leaving little room for anything for the routine to operate on. VIEWFRAME Faced with a desire to learn more about how my Newton MessagePad works than was documented, and a lack of really good tools to do so, I decided to write my own object browsing utility. I wanted something that could meaningfully display any NewtonScript object, and had no limitations on what objects could be viewed. This program, which ended up being called ViewFrame, is obviously going to be a work-in-progress for as long as Apple continues to refine the Newton system. But even in its first version it is quite capable of showing you more of what's going on "under the hood" than any existing tool. Figure 1 below shows how ViewFrame displays the unidentified frame of the earlier examples: * Note that the debug slot's value ("protoPictureButton") from the object's prototype is shown in the listing for the _proto slot, saving you the effort of opening that slot to see what it is. * Notice the @nnn notations that appear in several places. These are magic pointers, an important NewtonScript construct that is unfortunately discussed only briefly in current documentation. By looking them up in the NTK Definitions file you can tell exactly what the referenced object is. In this case the _proto is an object named protoPictureButton (already identified by the debug slot), and the icon is named ROM_cancelbitmap. The object itself is finally identified as the protoCancelButton. Hint: you can identify magic pointers using other debugging tools, too. Subtract three from an object's reference value, then divide by four. If the result is an integer, that's the magic pointer number for the object. This is probably not guaranteed to remain true for future Newton devices, but it's a quite useful trick for now. [There is also a function called IsMagicPtr. Ed]. Figure 2 shows more examples of ViewFrame's object displays, from slots in the protoCancelButton frame. Icons and pictures are displayed in graphical form, and currently eight common types of flags fields can be displayed as symbolic constants. Even NewtonScript functions can be displayed as an approximation of the original source code, although the results aren't always as accurate as in the example (the current version of ViewFrame can't fully interpret looping and conditional constructs). OTHER FEATURES ViewFrame has quite a few other features: * In addition to the object types shown in the examples, there are specific view formats for sounds (which are played), soup entries, strings and other types. Many object types have an alternate view format. For example, the icon above can be viewed as its component binary objects, if you really want to see that information * ViewFrame's window is fully resizeable, so you can have it take up the whole screen if you don't need to see anything else at the same time. If the full screen isn't enough area, you can dump the output to the Inspector if it's connected. * The contents of Newton dictionaries (other than lexical dictionaries, such as the phone numbers recognizer) can be dumped to the Inspector. * You can navigate the Newton object hierarchy by either tapping on slots or entering expressions at the top of the window. Tapping the diamond in the upper lefthand corner of the ViewFrame window brings up a list of expressions you can use, including common places to start browsing such as GetRoot() and GetGlobals(), and expressions relevant to the current object such as :ChildViewFrames(), when the object is an open view. Almost any NewtonScript operation can be executed using ViewFrame by entering the proper expressions. For example, by using the functions GetStores(), :GetSoup(), Query(), :Entry() and :Next() , all of which appear in the expression list at the appropriate time, you can examine the contents of any soup. * Programs that you write can call ViewFrame directly to display an arbitrary object, using a statement such as: GetRoot().|ViewFrame:JRH|:?NewValue( description, object); It's hardly as convenient as using a simple print() statement to send output to the Inspector, but can be used at times when the Inspector is unusable (such as while debugging a program that uses serial I/O). ACCESSORIES In order to make it easy to experiment with NewtonScript code, I wrote a companion program called the ViewFrame Editor (see Figure 3). It looks and acts much like the Newton Notepad, except that drawn shapes are not allowed. The returned value from programs you enter can be displayed using ViewFrame, so you don't have to worry about formatting the return value in a human-readable form. The Editor supports scrolling, so program size is limited only by available memory. In order to make NewtonScript entry practical in the ViewFrame Editor and the expression entry area of ViewFrame itself, I also created a Programmer's Keyboard (shown in Figure 3). It works the same as the standard on-screen keyboard (except that entry of words into your personal dictionary isn't supported), but also has several common NewtonScript phrases and punctuation marks available for entry with a single tap. For example, "viewSetupFormScript" can be typed in with only seven taps: "view", "Setup" and "Script" require only one tap each. As an added bonus, the Keyboard can be switched to a Dvorak layout for those of you who are more comfortable with that. AVAILBILITY As I mentioned, ViewFrame is a work in progress. By the time you read this, current owners should have already received a free editor upgrade. In addition, there are a variety of new features that I'm working on. Judging by the response from the Newton developer community, it's a very useful utility