| 001
#include <stdio.h> |
First some theory. Like most modern
computers, the Amiga uses a multi-tasking operating system. This means that
more than one program can be running on the Amiga at any given time. These programs
all share the same resources (i.e. memory, processor, keyboard, mouse, etc.).
It is the job of the operating system to sort out which program gets access
to the computer's resources and for how long it is given access. The OS also
determines which program any given input (keyboard input, mouse input, etc.)
is meant for.
The Amiga uses a system of messages and ports to communicate these kinds of
events to the various running programs. This is essentially setup like
a postal system. When a program opens a window, that window creates a message
port which is kind of like a mail box. Whenever anything of interest happens
to that window the OS sends a message to the associated message port with details
about the event. The OS also sets a flag (called a signal) to notify the program
that it has a message waiting. We can specify which messages we would like to
be notified of by using the WA_IDCMP tag when defining the
window. This tag is followed by a list of messages we will be notified of, all
other messages will be ignored. On to the program...
Take a look at lines 16 through 20. These five lines set up the variables needed
to monitor window messages on the Amiga. The first varible is called signals and is an unsigned long (i.e. 4 byte, 32
bit) value. The definition ULONG
is an Amiga specific definition that is found in the exec/types.h include
file. There are many other useful defines in exec/types.h, feel free
to examine this file to find out what other defines are made. We will cover
many of them in our tutorials.
The variable signals
will be used to hold the list of signals that the program will respond to. Signals
are used by Amiga OS to inform programs of certain events. For instance, many
programs respond to the control-C key combination. This key combination sets
a particular bit in the program's "signal mask". Once that bit is set, the program
can read the signals and take the proper action required to close. Sometimes
a program will not be able to check the state of its signal mask because it
is caught in an endless loop and will therefore not receive notice that the
control-C combination has been pressed; the program is then considered "frozen"
or "hanging". It is up to the programmer to ensure that the signal mask is checked
periodically.
Line 17 declares a pointer to an IntuiMessage structure. The Amiga
has several different types of messages that it sends back and forth to accomplish
particular tasks. Messages that are sent because of an event that occurred on
the Workbench screen are called Intuition Messages or IntuiMessages. Our variable message
points to the location of the next message we have received.
Note: For reasons of efficiency, the Amiga system of messages does not
really send messages to and fro. The reason for this is that a message can be
arbitrarily large and copying a message to another location in memory could
take quite a long time. So instead of sending the actual message, only the location
(or address in memory) of the message is sent. Sending the address of the message
only requires copying 4 bytes regardless of the size of the actual message.
The recipient program can then go to that location and read the message directly.
Lines 18 and 19 are used as temporary storage spaces for information in the
message. IntuiMessages
come in different "classes". Each of these classes have different "codes" that
signify particular messages. These two lines reserve space to hold a message's
class and code for later use. Line 20 declares a boolean (BOOL)
variable (a variable that can be either TRUE
or FALSE) for use in testing if the close
button has been pressed. It is set to FALSE
at the beginning of the program.
Line 39 adds a new tag to the window definition. WA_IDCMP
is the tag that tells workbench to notify our program if the window receives
any messages. The tag is followed by a list of the messages that we want to
be notified about. In our case, we only want to know about one message: IDCMP_CLOSEWINDOW. If there were
more than one message that we wanted to know about we would separate the messages
with the "or" ("|") operator.
Line 70 is the beginning of our loop. It consists of a while
statement followed by a test. When the program encounters a while
statement it first evaluates the test to its right. If the test is true then
it performs the code in the block below the while
statement, otherwise it skips the block completely. Every time the end of the
block is reached the test is evaluated again and the loop continues only if
it remains true. In our case the test reads "while not end
and MyWindow".
The loop will only begin if both the variable end
is FALSE
and the MyWindow structure
pointer is not NULL.
Testing the MyWindow
pointer ensures that the window has been opened. It would be pointless (or worse)
to wait for a message from a window that was not even opened.
At line 72, SetSignal() places a snapshot of the current signal bits into the variable signals. and line 70 tests to see if the message signal bit is set. If this bit is set then we have messages waiting and should check them as soon as possible. Note that we are not working directly with the signal bits, only a copy of them. This ensures that we don't accidentally change the bits or try to access them while they are being changed by the OS.
If the message bit is set, the program jumps to line 79 where we use GetMsg() to copy the address of the first
message found in our window's message port, namely MyWindow->UserPort. We must cast the resulting pointer as
an IntuiMessage
* because by default the GetMsg() function assumes that it is
dealing with normal Messages. IntuiMessages tack on some additional
information to the end of the message and we want to have access to that information.
Lines 82 and 83 copy the information that we require into some temporary variables.
Line 86 uses the ReplyMsg()
function to inform the OS that we have looked at the message and it is now ok
to remove it from the message port. Note that we had to cast message
back to a Message * to ensure that it is removed correctly. It is
important that messages are replied to promptly. Letting messages pile up in
the message port is not advised.
Also notice how we again deal with copies of the message data rather than the
actual data. This allows us to reply to the message more quickly and frees up
the message port for other messages. Once we are signaled that a message is
waiting the goal is the get the message, copy the needed information from it,
and reply to it as quickly as possible. Not replying quickly can lead to degraded
performance of the application or OS.
After we have replied to the message the program continues on the line 89. This
switch
statement takes the appropriate action based on the message's class. In our
case the only message class that we are concerned about is the IDCMP_CLOSEWINDOW class which is
the first case.
This particular class doesn't have any additional codes, but many other classes
of messages do have codes that give us additional information about the message.
Once the message class has been identified we can take the appropriate action.
In our case, the appropriate action is the set end equal to TRUE so that
the main loop exits the next time around and then the program closes.
Before the program closes, however, we need to make sure that all the messages
have been answered. This is why the GetMsg() function is part of a while loop condition. As long as
there are more messages in the message port we must process them and reply to
each one. Once we have responded to all the messages, the GetMsg() function returns NULL and the
program can continue on. It should be clear that the fewer messages that we
have to process, the faster our program can continue on with other, possibly
more interesting, tasks. This, again, is why it is important to not allow messages
to pile up in the message port.
If an IDCMP_CLOSEWINDOW message has been
received, then end
is TRUE
and the while loop condition at line 70
fails, otherwise the program continues to process messages as they arrive at
the message port. Once the loop has been exited the program cleans itself up
just as it did in simple_window.c by first closing MyWindow
and then closing the intuition.library.
And that's it really. Next time we will talk more about these messages and use
them to create a simple drawing program.
Last updated on
Sunday, November 27, 2005 23:22