When Amiga was released in 1985 the availability of two interfaces to interact with the computer was quite a novel feature. Amiga's can be operated via command line interface and graphical user interface. For the latter free movable windows are very important. In this tutorial we will open a window using AmigaOS routines and perform some simple drawing. Along the way we have to deal with Tags, variable parameter, messaging, drawing principles and intuition structures.
The part of AmigaOS that handles Windows, Mouse and/or Keyboard input is named Intuition and is accessible by the developer through intuition.library and can be combined with use of graphics.library for drawing routines. There are more things involved but these two libraries are the most important. Both libraries with their functions can be accessed in Free Pascal with the units named intuition and agraphics. The latter had to be named AGraphics because Free Pascal itself already has a (generic) unit named graphics and which is available in the Lazarus component library. To prevent issues due to name collision we decided to change the name for Amiga platforms to agraphics. Unfortunately we have to deal with such name collisions for some of the units/libraries and also applies to some of the declared structures. A list with names that had to be changed can be found at our Specifics wiki Page.
Some really cool innovations that the Amiga offers are hidden from the average user. The Taglist feature is such an innovation. Imagine you want to design a function that opens a window and which requires a lot of parameters in order to accomplish this. F.e. x and y coordinates, width, height, the type of window and even more if wanted. If you want to put them all into the parameter list of a declaration of a function or procedure then the list of parameters will become significant in length quickly and because of that such a lengthy list becomes very tedious to use. Usually such long lists of parameters can be avoided by using a record instead so that you would only have to supply a pointer to this record and which could then contain all parameters and other relevant information. But, after years of developing you'll notice that you need to add more and more parameters simply because more and more (powerful) features are added to their parameter list in order to be able to make use of this newly added window functionality.
One way to solve that without destroying compatibility to old programs is, to create a new function or record which includes these new fields as well. MS-Windows for example did that very often. You will find many functions/records with an additional suffix "Ex" which is the extended version that is able to support new properties.
Amiga took a different path: Tags. You supply a list of Tags and Value pairs to the function. Every supplied Tag is just a simple integer number and corresponds to a single property of the window. Just as an example (a fictional example though, let's assume we have the following TAG-value-pairs: Left = 1, Top = 2, Width = 3, Height = 4). If we also assume that you ignore all Tags that you don't know about and by default fill all other (unknown) properties which are not provided with some meaningful default values then this offers a rather ingenious and clever way of being able to add new tag properties to such a tag-list without actually breaking either backward or forward compatibility.
A taglist could look like this (this is actually part of a real taglist that is used to open a window):
As can been seen from the table above, there are different types (integer, string and boolean) that can be assigned as a Tag-value although the Tag's property name itself dictates which type that should actually be. But, in order to keep things simple we should be able to transfer all these different types using the same interface. There is a very simple but rather clever way that can solve this problem for us and that is by declaring tag values to be of type "PtrUInt" (or "NativeUInt", which is the same). This type is an unsigned integer value which is guaranteed to have enough room in order to even store a pointer. This way we are able to supply all our Tag-Values by simply casting them to PtrUInt. For example strings can be converted this way as a PChar (zero terminated C like strings) and would then be treated as any other common Pointer. Instead of casting (which is a rather tedious thing to do) there is also another solution available and that is offered by unit Utility, that offers a special set of wrapper functions named AsTag(). AsTag() will automatically convert all possible types into a PtrUint. Another notable feature of such tag-lists is that the list itself always needs to end with a special closing tag named TAG_END. That let every other function that work with tag-lists know where the actual end of the list is located. The TAG_END-Tag does not really require an actual tag-value. Since its common for a picture to be able to tell more than a thousand words, adding a list of tag-value pairs to a list looks something like:
Free Pascal is smart enough to create the string for WA_Title as type PChar. Be aware that this is not possible if the string is calculated at this point. Besides that, we also have to take into account whether or not the PChar that is going to be supplied to the function is copied or not (but more on that later).
Now, with all this gained knowledge let's try to open a window om our workbench. The Amiga Api offers quite some different functions that open a window:
- OpenWindow()  - This is an older declaration/interface that was used before taglists where invented but is still available for compatibility reasons.
- OpenWindowTagList()  - This function requires a link to a tag-list for the second parameter. You create the tag-list before making the actual call to the function. This is very convenient in case you wish to manipulate the tag-list beforehand or programmaticaly.
- OpenWindowTags()  - This function has a
array of PtrUIntas second parameter which can be used to directly supply a list of tags and corresponding tag-values to the function.