TweetFollow Us on Twitter

MACINTOSH C CARBON
MACINTOSH C CARBON: A Hobbyist's Guide To Programming the Macintosh in C
Version 1.0
© 2001 K. J. Bricknell
Go to Contents Go to Program Listing

CHAPTER 2

THE CLASSIC EVENT MANAGER - LOW-LEVEL AND OPERATING SYSTEM EVENTS

The Two Event Managers

As stated at Chapter 1, there are two managers in the system software's Human Interface Group that pertain to the subject of events. These two managers are:

  • The Event Manager (often unofficially referred to, in the Carbon era, as the Classic Event Manager).

  • The somewhat more sophisticated Carbon Event Manager, which was introduced with Carbon.

Carbon applications may utilise either of these two event models. This chapter addresses the Classic event model. The Carbon event model is addressed at Chapter 17.

Overview of the Classic Event Model

The Main Event Loop

Any Macintosh application displays one essential characteristic: it is event-driven. At its most basic level, the applicationŐs general strategy is to retrieve an event (such as a key press or a mouse click), process it, retrieve the next event, process it, and so on indefinitely until the user quits the application. The core of the application is thus the main event loop (see Fig 1).

If no events are pending for the active application at a particular time, that application can choose to relinquish control of the CPU (central processing unit, or microprocessor) for a specified amount of time before again checking to see whether an event has occurred. Events are retrieved, and processor time is relinquished, using the WaitNextEvent function. The WaitNextEvent function is, in a sense, the core of the Classic event model.

Information about a received event is placed in an event structure. An application may specify which types of events it wants to receive by including an event mask as a parameter in certain Event Manager functions.

Categories of Events

An application can receive many types of events. It can also send certain types of events to other applications. Events are broadly categorised as low-level events, Operating System events, and high-level events. The high-level event is the category of event used to send events to other applications.

Of the three categories, this chapter is concerned only with low-level events and Operating System events. High-level events are addressed at Chapter 10.

Low Level Events

Low-level events, which are sent to the application by the Toolbox Event Manager, are originated by such low-level occurrences as pressing and releasing a key and pressing and releasing the mouse button and inserting a disk.

The Window Manager also originates low-level events, specifically, two events relating to an application's windows:

  • The activate event, which has to do with informing the application to make changes to the appearance of a window depending on whether or not it is the frontmost window.

  • The update event, which has to do with informing the application to re-draw a window's contents.

The event that reports that the Event Manager has no other events to report (the null event) is also categorised as a low-level event.

Low-level events, except for update events and null events, are invariably directed to the foreground process only.

Operating System Events

Operating system events are returned to the application when the operating status of an application changes. For example, when an application has been switched to the background, the Process Manager sends it a suspend event. Then, when the application is switched back to the foreground, the Process Manager sends it a resume event.

Another Operating System event, called the mouse-moved event, is sent when the mouse pointer is moved outside a designated region.

Processes and Events

The subject of processes is of some relevance to the subject of events, more particularly to operating sustem events.

Ordinarily, a user will have more than one application running at the one time. The active application (the application with which the user is currently interacting) is known as the foreground process. The remaining open applications, if any, are known as background processes. The user can bring a background process to the foreground by, for example, clicking in one of its windows. When an application is switched between background and foreground in this way, a major switch is said to have occurred.

The foreground process has first priority for accessing the CPU, background processes accessing the CPU only when the foreground process yields time to them. Any application whose 'SIZE' resource (see below) specifies that it should receive null events when it is in the background is eligible for CPU time when it is not in the foreground. A minor switch is said to have occurred when a background process gains a period of CPU access without being brought to the foreground.

Low-Level and Operating System Events, System Software, and Applications

Fig 2 shows the relationship between low-level and Operating System events, system software managers and open applications.

In Fig 2, note that, in addition to the Operating System event queue created by the Operating System Event Manager, the Toolbox Event Manager maintains a separate event stream for each open application. An event stream contains only those events which are available to the related application. Also note that, when an application is in the background, its event stream can contain only update events, null events, and suspend events, the latter two only if the application's 'SIZE' resource so specifies.

An application in the background can also receive high-level events. (See Chapter 10.)

A maximum of 48 events can be pending in the Operating System event queue. If the queue becomes full, the oldest event is discarded to make room for the new.

Priority of Events

In general, the Event Manager returns events to the application in the order low-level events, Operating System events, and high-level events. In detail, the order of priority is:

  • Activate events.

  • Mouse-down, mouse-up, key-down, key-up and disk events in FIFO (first in, first out) order.

  • Auto-key events.

  • Update events, in front-to-back order of windows.

  • Operating system events.

  • High-level events.

  • Null events.

Obtaining Information About Events

The Event Structure

The Event Manager continually captures information about each keystroke, mouse click, etc., and puts information about each event into an event structure. As more actions occur, additional event structures are created and joined to the first, forming an event queue.

The EventRecord data type defines the event structure:

     struct EventRecord
     {
       EventKind      what;
       UInt32         message;
       UInt32         when;
       Point          where;
       EventModifiers modifiers;
     };

     typedef struct EventRecord EventRecord;

Field Descriptions

what

Indicates the type of event received, which may be represented by one of the following constants:

nullEvent        = 0   No other pending events.
mouseDown        = 1   Mouse button pressed.
mouseUp          = 2   Mouse button released.
keyDown          = 3   Character key pressed.
keyUp            = 4   Character key released.
autoKey          = 5   Key held down in excess of autoKey threshold.
updateEvt        = 6   Window needs to be redrawn.
activateEvt      = 8   Activate/deactivate window.
osEvt            = 15  Operating system event (suspend, resume, mouse moved).
message

Contains additional information about the event. The content of this field depends on the event type, as follows:

Event Type

Contents of message Field

nullEvent
mouseDown
mouseUp

Undefined.

keyDown
keyUp
autoKey

Bits 0-7 = character code. Bits 8-15 = virtual key code.
Bits 16-23 = For Apple Desktop Bus keyboards, the ADB address of the keyboard where the event occurred.

updateEvt
activateEvt

Pointer to the window to update, activate or deactivate. (For an activateEvt, Bit 0 of the modifiers field indicates whether to activate or deactivate the window.)

osEvt resume

Bits 24-31 = suspendResumeMessage constant.
Also, a 1 in Bit 0 to indicate that the event is a resume event.
Also, a 0 or a 1 in Bit 1 to indicate if clipboard conversion is required.

osEvt suspend

Bits 24-31 = suspendResumeMessage constant.
Also, a 0 in Bit 0 to indicate that the event is a suspend event.

osEvt mouse-moved

Bits 24-31 = mouseMovedMessage constant.

The following constants may be used to extract certain data from, and to test certain bits in, the message field:

charCodeMask          = 0x000000FF  Mask to extract ASCII character code.
keyCodeMask           = 0x0000FF00  Mask to extract key code.
osEvtMessageMask      = 0xFF000000  Mask to extract OS event message code.
mouseMovedMessage     = 0x00FA      osEvts: mouse-moved event?
suspendResumeMessage  = 0x0001      osEvts: suspend/resume event?
resumeFlag            = 1           osEvts: resume event or suspend event?

For example, the following code example determines whether an event which has previously been determined to be an Operating System event is a resume event, a suspend event, or a mouse-moved event. In this example, the high byte of the message field is examined to determine whether it contains suspendResumeMessage (0x0001) or mouseMovedMessage (0x00FA). If it contains suspendResumeMessage, Bit 0 is then examined to determine whether the event is a suspend event or a resume event.

switch((eventStrucPtr->message >> 24) & 0x000000FF)
{
  case suspendResumeMessage:
    if((eventRecPtr->message & resumeFlag) == 1)
      // This is a resume event.
    else
      // This is a suspend event.
    break;
      
  case mouseMovedMessage:
    // This is a mouse-moved event.
    break;
}
when

Time the event was posted, in ticks since system startup. (A tick is approximately 1/60th of a second.) Typically, this is used to establish the time between mouse clicks.

where

Location of cursor, in global coordinates, at the time the event was posted. (Global coordinates are explained at Chapter 4.)

modifiers

Contains information about the state of the modifier keys and the mouse button at the time the event was posted.

For activate events, this field indicates whether the window should be activated or deactivated.

For mouse-down events, this field indicates whether the event caused the application to be switched to the foreground.

Bit

Description

Bit 0

activateEvt: 1 if the window pointed to in the message field should be activated. 0 if the window pointed to in the message field should be deactivated.
mouseDown: 1 if the event caused the application to be switched to the foreground, otherwise 0.

Bit 7

1 if mouse button was up, 0 if not.

Bit 8

1 if Command key down, 0 if not.

Bit 9

1 if Shiftkey down, 0 if not.

Bit 10

1 if Caps Lock key down, 0 if not.

Bit 11

1 if Option key down, 0 if not.

Bit 12

1 if Control key down, 0 if not.

Bit 13

1 if Right Shift key down, 0 if not.

Bit 14

1 if Right Option key down, 0 if not.

Bit 15

1 if Right Control key down, 0 if not.

The following constants may be used as masks to test the setting of the various bits in the modifiers field:

activeFlag      = 0x0001  Window is to be activated? (activateEvt).
                          Foreground switch? (mouseDown).
btnState        = 0x0080  Mouse button up?
cmdKey          = 0x0100  Command key down?
shiftKey        = 0x0200  Shift key down?
alphaLock       = 0x0400  Caps Lock key down?
optionKey       = 0x0800  Option key down?
controlKey      = 0x1000  Control key down?
rightShiftKey   = 0x2000  Right Shift Key down?
rightOptionKey  = 0x4000  Right Option Key down?
rightControlKey = 0x8000  Right Control Key down?

For example, the following code example determines whether an event which has previously been determined to be an activate event is intended to signal the application to activate or deactivate the window referenced in the message field:

Boolean becomingActive;

becomingActive = ((eventStrucPtr->modifiers & activeFlag) == activeFlag);

if(becomingActive)
  // Window activation code here.
else
  // Window deactivation code here.

Event Structure Examples - Diagrammatic

Fig 3 is a diagrammatic representation of the contents of some typical event structures.

The WaitNextEvent Function

The WaitNextEvent function retrieves events from the Event Manager. If no events are pending for the application, the WaitNextEvent function may allocate processor time to other applications. When WaitNextEvent returns, the event structure contains information about the retrieved event, if any.

WaitNextEvent returns true if it retrieves any event other than a null event. If there are no events of the types specified in the eventMask parameter (other than null events), false is returned.

Boolean  WaitNextEvent(EventMask eventMask, EventRecord *theEvent,
                       UInt32 sleep, RgnHandle mouseRgn)

Returns: A return code: 0  = null event; 1 = event returned.
eventMask

A 16 bit binary mask which may be used to mask out the receipt of certain events. The following constants are defined in Events.h:

mDownMask          = 0x0002  Mouse button pressed.
mUpMask            = 0x0004  Mouse button released.
keyDownMask        = 0x0008  Key pressed.
keyUpMask          = 0x0010  Key released.
autoKeyMask        = 0x0020  Key repeatedly held down.
updateMask         = 0x0040  Window needs updating.
diskMask           = 0x0080  Disk inserted.
activMask          = 0x0100  Activate/deactivate window.
highLevelEventMask = 0x0400  High-level events (includes AppleEvents).
osMask             = 0x8000  Operating system events (suspend, resume).
everyEvent         = 0xFFFF  All of the above.

Masked events are not removed from the event stream by the WaitNextEvent call. To remove events from the Operating System event queue, call FlushEvents with the appropriate mask.

theEvent

Address of a 16-byte event record.

sleep

On the cooperative multitasking (see below) Mac OS 8/9, the sleep parameter specifies the amount of time, in ticks, the application agrees to relinquish the processor if no events are pending for it. If no events are received during this period, WaitNextEvent returns 0, with a a null event in the theEvent parameter, at the expiration of the sleep period.

On the preemptive multitasking (see below) Mac OS X, the sleep parameter is not ignored. It simply causes WaitNextEvent to block for the specified period or until an event arrives.

 

In order to give drivers time to run, the Classic WaitNextEvent will often return long before the sleep time that you pass to it has expired. The Carbon WaitNextEvent does not do this; it always waits the full sleep time.

mouseRgn

The screen region inside which the Event Manager does not generate mouse-moved events. The region should be specified in global coordinates. If the user moves the cursor outside this region and the application is the foreground process, the Event Manager reports mouse-moved events.

If NULL is passed as this parameter, the Event Manager does not return mouse- moved events.

Before returning to the application, WaitNextEvent performs certain additional processing and may, in fact, intercept the received event so that it is never received by your application. As will be seen, key-up and key-down events are intercepted in this way in certain circumstances.

The sleep Parameter and Multitasking

Cooperative Multitasking - Mac OS 8/9

The yielding of access to the CPU by the foreground process, via WaitNextEvent's sleep parameter, is central to the form of multitasking provided by the Mac OS 8/9 system software. That form of multitasking is known as cooperative multitasking.

Under cooperative multitasking, individual applications continue executing until they "decide" to release control, thus allowing the background process of another application to begin executing. Even though this results in a usable form of multitasking, the operating system itself does not control the processor's scheduling. Even under the best of circumstances, an individual application (which has no way of knowing what other applications are running or whether they have a greater "need" to execute) makes inefficient use of the processor, which often results in the processor idling when it could be used for productive work.

Note also that, under this cooperative scheme, the assignment of zero to WaitNextEvent's sleep parameter will cause your application to completely "hog" the CPU whenever it is in the foreground, allowing no CPU time at all to the background processes.

Preemptive Multitasking - Mac OS X

Under preemptive multitasking, the operating system itself retains control of which body of code executes, and for how long. No longer does one task have to depend on the good will of another task - that is, the second task's surrender of control - to gain access to the CPU.

Flushing the Operating System Event Queue

Immediately after application launch, the FlushEvents function should be called to empty the Operating System event queue of any low-level events left unprocessed by another application, for example, any mouse-down or keyboard events that the user may have entered while the Finder launched the application.

Handling Events

Handling Mouse Events

Events related to the movement of the mouse are not stored in the event queue. The mouse driver automatically tracks the mouse and displays the cursor as the user moves the mouse.

Your application receives mouse-down events only when it is the foreground process and the user clicks in a window belonging to the application or in the menu bar, (If the user clicks in a window belonging to another application, your application receives a suspend event.)

The first action on receipt of a mouse-down event is to determine where the cursor was when the mouse button was pressed. A call to FindWindow will determine:

  • Which of your application's windows, if any, the mouse button was pressed in.

  • Which window part the mouse button was pressed in. In this context, a window part includes the menu bar as well as various regions within the window.

The following constants, defined in MacWindows.h, may be used to test the value returned by FindWindow:

     inDesk    = 0   In none of the following.
     inNoWindow     = 0   In none of the following.
     inMenuBar      = 1   In the menu bar.
     inContent      = 3   Anywhere in the content region except the grow region
                          if the window is active.  Anywhere in the content region
                          including the grow region if the window is inactive.
     inDrag         = 4   In the drag region.
     inGrow         = 5   In the grow/resize region (active window only).
     inGoAway       = 6   In the close region (active window only).
     inZoomIn       = 7   In the zoom-in region (active window only).
     inZoomOut      = 8   In the zoom-out region (active window only).
     inCollapseBox  = 11  In the collapse/minimize region (active window only).
     inProxyIcon    = 12  In the window proxy icon (active window only).

In the Content Region

If the cursor was in the content region of the active window, your application should perform the action that is appropriate to the application. If the window has scroll bars, and since scroll bars actually occupy part of the content region, your application should first determine whether the cursor was in the scroll bars - or, indeed, in any other control - and respond appropriately.

The content region is the part of the window in which an application displays the contents of a document and the window's controls (for example, scroll bars).

In the Title Bar, Size Box, Zoom Box, Close Box, Collapse Box, or Window Proxy Icon

In the following, Mac OS 8/9 terminology is used. Title bar equates to the Mac OS X title bar. Size box equates to resize control. Zoom box equates to zoom button. Close box equates to close button. Collapse box equates to minimise button.

If the cursor was in one of the non-content regions of the active window, your application should perform the appropriate actions for that region as follows:

  • Title Bar. If the cursor was in the title bar, your application should do one of the following:

    • Call DragWindow to allow the user to drag the window to a new location. DragWindow retains control until the mouse button is released. (See Chapter 4.)

    • Use an alternative approach introduced with the Mac OS 8.5 Window Manager which first involves a call to IsWindowPathSelect to determine whether the mouse-down event should activate the window path pop-up menu. If IsWindowPathSelect returns true, your application should then call WindowPathSelect to display the menu, otherwise your application should call DragWindow to allow the user to drag the window to a new location. (See Chapter 16.)

  • Size Box.If the cursor was in the size box, your application should call to ResizeWindow, which tracks user actions while the mouse button remains down. When the mouse button is released, ResizeWindow draws the window in its new size.

  • Zoom Box. If the cursor was in the zoom box, your application should call to IsWindowInStandardState to determine whether the window is currently in the standard state or the user state. ZoomWindowIdeal should then be called to zoom the window to the appropriate state, and the window's content region should be redrawn.

  • Close Box. If the cursor was in the close box, your application should call TrackGoAway to track user actions while the mouse button remains down. TrackGoAway, which returns only when the mouse is released, returns true if the cursor is still inside the close box when the mouse button is released, and false otherwise.

  • Collapse Box. If the cursor was in the collapse box, your application should do nothing, because the system will collapse (Mac OS 8/9) or minimise (Mac OS X) the window for you.

  • Window Proxy Icon. If the cursor was in the window proxy icon, your application should call TrackWindowProxyDrag, which handles all aspects of the drag process while the user drags the proxy icon. (See Chapter 16.)

In the Menu Bar

If the cursor was in the menu bar, your application should first adjust its menus, that is, enable and disable items and set marks (for, example, checkmarks) based on the context of the active window. It should then call MenuSelect, which handles all user action until the mouse button is released.

When the mouse button is released, MenuSelect returns a long integer containing, ordinarily, the menu ID in the high word and the chosen menu item in the low word. However, if the cursor was outside the menu when the button was released, the high word contains 0.

In an Inactive Application Window

If the mouse click was in an inactive application window, FindWindow can return only the inContent or inDrag constant. If inContent is reported, your application should bring the inactive window to the front using SelectWindow.

Ordinarily, the first click in an inactive window should simply activate the window and do nothing more. However, if the mouse click is in the title bar, for example, you could elect to have your application activate the window and allow the user to drag the window to a new location, all on the basis of the first mouse-down.

Detecting Mouse Double Clicks

Double clicks can be detected by comparing the time of a mouse-up event with that of an immediately following mouse-down. GetDoubleTime returns the time difference required for two mouse clicks to be interpreted as a double click.

Handling Keyboard Events

After retrieving a key-down event, an application should determine which key was pressed and which modifier keys (if any) were pressed at the same time. Your application should respond appropriately when the user presses a key, or combination of keys. For example, your application should allow the user to choose a frequently used menu command by using its keyboard equivalent.

Character Code and Virtual Key Code

The low-order word in the message field contains the character code and virtual key code corresponding to the key pressed by the user.

For a specific key on a particular keyboard, the virtual key code is always the same. The system uses a key-map ('KMAP') resource to determine the virtual key code that corresponds to a specific physical key,

The system software then takes this virtual key code and uses a keyboard layout ('KCHR') resource to map the virtual keycode to a specific character code. Any given script system (that is, writing system) has one or more 'KCHR' resources (for example, a French 'KCHR' and a U.S. 'KCHR') which determine whether virtual key codes are mapped to, again for example, the French or the U.S. character set.

Generally speaking, your application should use the character code rather than the virtual key code when responding to keyboard events. The following constants may be used as masks to access the virtual key code and character code in the message field:

     keyCodeMask   = 0x0000FF00  Mask to extract key code.
     charCodeMask  = 0x000000FF  Mask to extract ASCII character code.

Checking for Keyboard Equivalents

In its initial handling of key-down and auto-key events, the application should first extract the character code from the message field and then check the modifiers field to determine if the Command key was pressed at the time of the event. If the Command key was down, the menus should be adjusted prior to further processing of the event. This further processing must necessarily accommodate the possibility that one or more of the modifier keys (Shift, Option, and Control) were also down at the same time as the Command key. If the Command key was not down, the appropriate function should be called to further handle the event.

A menu item can be assigned a keyboard equivalent, that is, any combination of the Command key, optionally one or more modifier keys (Shift, Option, Control), and another key. A Command-key equivalent such as Command-C is thus, by definition, also a keyboard equivalent.

Checking For a Command-Period Key Combination

Your application should allow the user to cancel a lengthy operation by using the Command-period combination. This can be implemented by periodically examining the state of the keyboard using GetKeys or, alternatively, by calling CheckEventQueueForUserCancel to scan the event queue for a Command-period keyboard event. The demonstration program at Chapter 25 contains a demonstration of the latter method.

Events Not Returned to the Application

Certain keyboard events will not, or may not, be returned to your application. These are as follows:

  • Command-Shift-Numeric Key Combinations. Some keystroke combinations are handled by the Event Manager and are thus not returned to your application. These include certain Command-Shift-numeric key combinations, for example (on Mac OS 8/9), Command-Shift-3 to take a snapshot of the screen. These key combinations invoke a function that takes no parameters and which is stored in an 'FKEY' resource with a resource ID corresponding to the number key in the Command-Shift-numeric key combination. (Note that IDs of 1 to 4 are reserved by Apple.)

    Function key functions are not supported in Carbon.

  • Key-Up Events. At application launch, the Operating System initialises another event mask, called the system event mask, to exclude key-up messages. If an application needs to receive key-up events, the system event mask must be changed using the SetEventMask function.

Handling Update Events

Handling Update Events - Mac OS 8/9

The Update Region

On Mac OS 8/9, when one window covers another and the user moves the front window, the Window Manager generates an update event so that the contents of the newly exposed area of the rear window can be updated, that is, redrawn.

The Window Manager keeps track of all areas of a window's content region that need to be redrawn and accumulates them in a region called the update region. When the application calls WaitNextEvent, the Event Manager determines whether any windows have a non-empty update region. If a non-empty update region is found, the Event Manager reports an update event to the appropriate application. Update events are issued for the front window first when more than one window needs updating,

Updating the Window

Upon receiving the update event, your application should first call BeginUpdate, which temporarily replaces the visible region of the window's graphics port with the intersection of the visible region and the update region and then clears the update region. (If the update region is not cleared, the Event Manager will continue to send an endless stream of update events. Accordingly, it is absolutely essential that BeginUpdate be called in response to all update events.)

This process is explained in more detail at Chapter 4.

Your application should then draw the window's contents. (Note that, to prevent the unnecessary drawing of unaffected areas of the window, the system limits redrawing to the visible region, which at this point corresponds to the update region as it was before BeginUpdate cleared it.)

EndUpdate should then be called to restore the normal visible region.

Update functions should first determine if the window is a document window or a modeless dialog box and call separate functions for redrawing the window or the dialog box accordingly. (See Chapter 8.)

Handling Update Events - Mac OS X

On Mac OS X, windows are double-buffered, meaning that your application does not draw into the window's graphics port itself but rather into a separate buffer. The Window Manager flushes the buffer to the window's graphics port when your application calls WaitNextEvent. On Mac OS X, your application does not require update events to cater for the situation where part, or all, of a window's content region has just been exposed as a result of the user moving an overlaying window.

On Mac OS X, the receipt of an update event simply means that your application should draw the required contents of the window. The swapping of visible and update regions required on Mac OS 8/9 is not required, so calls to BeginUpdate and EndUpdate are irrelevant (and ignored) on Mac OS X.

Updating Windows in the Background

Recall that your application will receive update events when it is in the background if the application's 'SIZE' resource so specifies.

Handling Activate Events

Whenever your application receives a mouse-down event, it should first call FindWindow to determine if the user clicked in a window other than the active window. If the click was, in fact, in a window other than the active window, SelectWindow should be called to begin the process of activating that window and deactivating the currently active window.

SelectWindow does some of the activation/deactivation work for you, such as removing the highlighting from the window being deactivated and highlighting the window being activated. It also generates two activate events so that, at your application's next two requests for an event, an activate event is returned for the window being deactivated followed by an activate event for the window being activated. In response, your application must complete the action begun by SelectWindow, performing such actions as are necessary to complete the activation or deactivation process. Such actions might include, for example, showing or hiding the scroll bars, restoring or removing highlighting from any selections, adjusting menus, etc.

The message field of the event structure contains a reference to the window being activated or deactivated and bit 0 of the modifiers field indicates whether the window is being activated or deactivated. The activeFlag constant may be used to test the state of this bit.

When the user switches between your application and another application, your application is notified of the switch through Operating System (suspend and resume) events.

In a Classic application, if the application's 'SIZE' resource has the acceptSuspendResumeEvents flag set and the doesActivateOnFGSwitch flag not set, your application receives an activate event immediately following all suspend and resume events. This means that the application can rely on the receipt of those activate events to trigger calls to its window activation/deactivation functions when a major switch occurs.

On the other hand, if a Classic application has both the acceptSuspendResumeEvents and the doesActivateOnFGSwitch flags set, it does not receive an activate event immediately following suspend and resume events. In this case, the application must call its window activation/deactivation functions whenever it receives a suspend or resume event, in addition to the usual call made in response to an activate event.

The generally accepted practise in Classic applications is to set the doesActivateOnFGSwitch flag whenever the acceptSuspendResumeEvents flag is set.

In a Carbon application, activate events are invariably received along with all suspend and resume events regardless of the doesActivateOnFGSwitch flag setting. This would suggest that the doesActivateOnFGSwitch flag is irrelevant in a Carbon application and need never be set. However, the correct generation of activate events requires that this flag always be set in a Carbon application.

The upshot is that, in Carbon applications, and despite the fact that the the doesActivateOnFGSwitch flag should still be set, window activation/deactivation functions need never be called on suspend and resume events.

Handling Null Events

The Event Manager reports a null event when the application requests an event and the application's event stream does not contain any of the requested event types. The WaitNextEvent function reports a null event by returning false and placing nullEvt in the what field.

When your application receives a null event, and assuming it is the foreground process, it can perform what is known as idle processing, such as blinking the insertion point caret in the active window of the application.

As previously stated, your application's 'SIZE' resource can specify that the application receive null events while it is in the background. If your application receives a null event while it is in the background, it can perform tasks or do other processing.

In order not to deny a reasonable amount of processor time to other applications, idle processing and background processing should generally be kept to a minimum.

Handling Suspend and Resume Events

When an Operating System event is received, the message field of the event structure should be tested with the constants suspendResumeMessage and mouseMovedMessage to determine what type of event was received. If this test reveals that the event was a suspend or resume event, bit 0 should be tested with the constant resumeFlag to ascertain whether the event was a suspend event or a resume event.

WaitNextEvent returns a suspend event when your application has been switched to the background and returns a resume event when your application becomes the foreground process.

There is a fundamental difference between the receipt of suspend events in Carbon applications as compared with Classic applications. In Classic applications, suspend events are received when your application is about to be switched to the background, that is, the application does not actually switch to the background until it makes its next request to receive an event from the Event Manager. In Carbon applications, suspend events are received after the application has been switched to the background.

On receipt of a suspend event, your application should do anything necessary to reflect the fact that it is now in the background. When an application receives a resume event, it should do anything necessary to reflect the fact that it is now in the foreground and set the mouse cursor to the arrow shape.

Handling Mouse-Moved Events

Mouse-moved events are used to trigger a change in the appearance of the cursor according to its position in a window. For example, when the user moves the cursor outside the text area of a document window, applications typically change its shape from the I-beam shape to the standard arrow shape.

The main requirement is to specify a region in the mouseRgn parameter of the WaitNextEvent function. This causes the Event Manager to report a mouse-moved event if the user moves the cursor outside that region. On receipt of the mouse-moved event, the application can change the shape of the cursor.

An application might define two regions: a region which encloses the text area of a window (the I-beam region) and a region which defines the scroll bars and all other areas outside the text area (the arrow region). By specifying the I-beam region to WaitNextEvent, the mouse driver continues to display the I-beam cursor until the user moves the cursor out of this region. When the cursor moves outside the region, WaitNextEvent reports a mouse-moved event. Your application can then change the I-beam cursor to the arrow cursor and change the mouseRgn parameter to the non-I-beam region. The cursor now remains an arrow until the user moves the cursor out of this region, at which point your application receives another mouse-moved event.

The application must, of course, recalculate and change the mouseRgn parameter immediately it receives a mouse-moved event. Otherwise, mouse-moved events will be continually received as long as the cursor is outside the original region.

The appearance of the cursor may be changed using the QuickDraw function SetCursor or the Appearance Manager function SetThemeCursor. (See Chapter 6 and Chapter 13.)

Cursor setting functions should account for whether a document window or modeless dialog box is active and set the cursor appropriately.

Handling Events in Alert Boxes and Dialog Boxes

The handling of events in alert boxes and dialog boxes is addressed in detail at Chapter 8. The following is a brief overview only.

Modal and Movable Modal Alert Boxes

The Dialog Manager functions Alert, NoteAlert, CautionAlert, StopAlert, and StandardAlert are used to invoke modal and movable modal alert boxes and to handle all user interaction while the alert box remains open. The Dialog Manager handles all the events generated by the user until the user clicks a button (typically, the OK or Cancel button). When the user clicks the OK or Cancel button, the Dialog Manager closes the alert box and reports the user's action to the application, which is responsible for performing any appropriate subsequent actions.

Modal and Movable Modal Dialog Boxes

For modal and movable modal dialog boxes, the Dialog Manager function ModalDialog is used to handle all user interaction while the dialog box is open. When the user selects an item, ModalDialog reports the selection to the application, in which case the application is responsible for performing the action associated with that item. An application typically calls ModalDialog repeatedly, responding to clicks on enabled items as reported by ModalDialog, until the user selects the OK or Cancel button.

Modeless Dialog Boxes

For modeless dialog boxes, you can use the function IsDialogEvent to determine whether the event occurred while a modeless dialog box was the frontmost window and then, optionally, use the function DialogSelect to handle the event if it belongs to a modeless dialog box. DialogSelect is similar to ModalDialog except that it returns control after every event, not just events relating to an enabled item.

The 'SIZE' Resource

Several references have been made in the preceding to the application's 'SIZE' resource because some (though not all) of the flag fields in this resource are relevant to the subject of events.

An application's 'SIZE' resource informs the Operating System:

  • About the memory requirements of the application.

  • About certain scheduling options (for example, whether the application can accept suspend and resume events).

  • Whether the application:

    • Supports stationery documents.

    • Supports TextEdit's inline input services.

    • Wishes to receive notification of the termination of any application it has launched.

    • Wishes to receive high-level events.

The 'SIZE' resource comprises a 16-bit flags field, which specifies the operating characteristics of your application, followed by two 32-bit size fields, one indicating the minimum size, and one the preferred size, of the application's partition.

Resource ID

The 'SIZE' resource created for your application should have a resource ID of -1. If, on Mac OS 8/9, the user modifies the preferred size in the Finder's Get Info window, the Operating System creates a new 'SIZE' resource having an ID of 0. If it exists, this latter resource will be invoked by the Operating System at application launch. If it does not exist, the Process Manager looks for the original 'SIZE' resource with ID -1.

Creating a 'SIZE' Resource in CodeWarrior

It is possible to create a 'SIZE' resource use Resorcerer; however, it is far more convenient to use the built-in 'SIZE' resource creation facility within CodeWarrior.

Flags Fields. In CodeWarrior, the bits of the flags field can be set as desired using the 'SIZE' Flags pop-up menu in the PPC Target sections of the Settings dialog box, which appears when Settings... is chosen from the Edit Menu. The following describes the meanings of the items in the pop-up menu, and thus of the relevant bits of the 16-bit flags field. Those items relevant to low-level and Operating System events appear on a blue background.

'SIZE' Flags Pop-Up Menu

Meaning When Set

Meaning When Not Set

acceptSuspendResumeEvents

Your application can process, and thus wants to receive, suspend and resume events. (When this flag is set, the doesActivateOnFGSwitch flag should also normally be set.)

Your application does not want to receive suspend and resume events.

canBackground

Your application wants to receive null event processing time while in the background.

Your application does no background processing and thus does not want to receive null events when it is in the background.

doesActivateOnFGSwitch

(In Classic applications, setting this flag means that your application does not want to receive activate events associated with suspend and resume events, and will thus activate and deactivate its windows in response to suspend and resume events as well as activate events.

In a Carbon application, activate events are invariably received along with all suspend and resume events regardless of the doesActivateOnFGSwitch flag setting. This would suggest that the doesActivateOnFGSwitch flag is irrelevant in a Carbon application and need never be set. However, the correct generation of activate events requires that this flag always be set in a Carbon application.)

onlyBackground

Your application runs only in the background. (Usually, this is because it does not have a user interface and cannot run in the foreground.)

Your application runs in the foreground and the background.

getFrontClicks

Your application wants to receive the mouse-down and mouse-up events that are used to bring your application into the foreground when the user clicks in your application's frontmost window.

Your application does not want to receive the mouse-down and mouse-up events that are used to bring your application into the foreground.

acceptAppDiedEvents

Your application wants to be notified whenever an application launched by your application terminates or crashes. (This information is received via an Apple event.)

Your application does not want to be notified whenever an application launched by your application terminates or crashes.

is32BitCompatible

(In pre-Mac OS 8 versions of the system software, setting this flag indicated that your application could be run with either the 32-bit Memory Manager or the 24-bit Memory Manager. Unsetting this flag inicated that your application could not be run with the 32-bit Memory Manager.

No Power Macintosh supports the 24-bit mode. Accordingly, this flag is irrelevant in Carbon and should be left unset.)

isHighLevelEventAware

Your application can send and receive high-level events. (Your application must support the four required Apple events (see Chapter 10) if this flag is set.)

The Event Manager does not give your application high-level events when it calls WaitNextEvent.

For reasons unknown, this flag must always be set in Carbon applications. If this flag is not set, this alert will appear at compile time "Could not launch (application name) because the library ">>CarbonLib<<" could not be found."

LocalAndRemoteHLEvents

Your application is to be visible to applications running on other computers on a network

Your application does not receive high-level events across a network.

isStationeryAware

Your application can recognise stationery documents.

Your application cannot recognise stationery documents. If the user opens a stationery document, the Finder duplicates the document and prompts the user for a name for the duplicate document.

useTextEditServices

Your application can use the inline text services provided by TextEdit.

Your application cannot use the inline text services provided by TextEdit.

isDisplayManagerAware

Your application can handle the Display Notice event, which tells your application to move its windows after the monitor settings have changed.

When the monitor settings are changed, the DisplayManager moves your application's windows so that they do not disappear off the screen.

Size Fields. For Mac OS 8/9, the minimum and preferred sizes of the application's partition may be set in the Preferred Heap Size (k) and MinimumHeap Size (k) sections of the PPC Target section of the Settings dialog box.

Main Event Manager Constants, Data Types and Functions

Constants

Event Codes

nullEvent    = 0   No other pending events.
mouseDown    = 1   Mouse button pressed.
mouseUp      = 2   Mouse button released.
keyDown      = 3   Character key pressed.
keyUp        = 4   Character key released.
autoKey      = 5   Key held down in excess of autoKey threshold.
updateEvt    = 6   Window needs to be redrawn.  
activateEvt  = 8   Activate/deactivate window.
osEvt        = 15  Operating system event (suspend, resume or mouse moved).

Event Masks

mDownMask           = 0x0002  Mouse button pressed.
mUpMask             = 0x0004  Mouse button released.
keyDownMask         = 0x0008  Key pressed.
keyUpMask           = 0x0010  Key released.
autoKeyMask         = 0x0020  Key repeatedly held down.
updateMask          = 0x0040  Window needs updating.
activMask           = 0x0100  Activate/deactivate window.
highLevelEventMask  = 0x0400  High-level events (includes AppleEvents).
osMask              = 0x8000  Operating system events (suspend, resume).
everyEvent          = 0xFFFF  All of the above.Event Message

Masks for Keyboard Events

keyCodeMask   = 0x0000FF00  Mask to extract key code.
charCodeMask  = 0x000000FF  Mask to extract ASCII character code.

Message Codes For Operating System Events

osEvtMessageMask      = 0xFF000000  Mask to extract OS event message code.
mouseMovedMessage     = 0x00FA      For osEvts, test for mouse-moved event.
suspendResumeMessage  = 0x0001      For osEvts, test for suspend/resume event.
resumeFlag            = 1           For osEvts, test Bit 0.

Constants Corresponding to Bits in the modifiers Field

activeFlag       = 0x0001  Set if window being activated (activateEvt).
                           Set if event caused a foreground switch (mouseDown).
btnState         = 0x0080  Set if mouse button up.
cmdKey           = 0x0100  Set if Command key down.
shiftKey         = 0x0200  Set if Shift key down.
alphaLock        = 0x0400  Set if Caps Lock key down.
optionKey        = 0x0800  Set if Option key down.
controlKey       = 0x1000  Set if Control key down.
rightShiftKey    = 0x2000  Set if Right Shift Key down.
rightOptionKey   = 0x4000  Set if Right Option Key down.
rightControlKey  = 0x8000  Set if Right Control Key down.

Data Types

Event Structure

struct EventRecord 
{
  EventKind       what;        // Event code.
  UInt32          message;     // Event message.
  UInt32          when;        // Ticks since system startup.
  Point           where;       // Mouse location in global coordinates.
  EventModifiers  modifiers;   // Modifier flags.
} EventRecord;

typedef struct EventRecord EventRecord;

Functions

Receiving Events

Boolean  WaitNextEvent(EventMask eventMask,EventRecord *theEvent,UInt32 sleep,
         RgnHandle mouseRgn);
Boolean  EventAvail(EventMask eventMask,EventRecord *theEvent);
void     FlushEvents(EventMask whichMask,EventMask stopMask);
Boolean  GetNextEvent(EventMask eventMask,EventRecord *  theEvent)
void     SetEventMask(EventMask value);

Reading the Mouse

void     GetMouse(Point *mouseLoc);
Boolean  Button(void);
Boolean  StillDown(void);
Boolean  WaitMouseUp(void);

Reading the KeyBoard

void     GetKeys(KeyMap theKeys);
UInt32   KeyTranslate(const void *transData,UInt16 keycode,UInt32 *state);

Getting Timing Information

UInt32   TickCount(void);
UInt32   GetDblTime(void);
UInt32   GetCaretTime(void);

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

The Legend of Heroes: Trails of Cold Ste...
I adore game series that have connecting lore and stories, which of course means the Legend of Heroes is very dear to me, Trails lore has been building for two decades. Excitedly, the next stage is upon us as Userjoy has announced the upcoming... | Read more »
Go from lowly lizard to wicked Wyvern in...
Do you like questing, and do you like dragons? If not then boy is this not the announcement for you, as Loongcheer Game has unveiled Quest Dragon: Idle Mobile Game. Yes, it is amazing Square Enix hasn’t sued them for copyright infringement, but... | Read more »
Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »

Price Scanner via MacPrices.net

Apple is offering significant discounts on 16...
Apple has a full line of 16″ M3 Pro and M3 Max MacBook Pros available, Certified Refurbished, starting at $2119 and ranging up to $600 off MSRP. Each model features a new outer case, shipping is free... Read more
Apple HomePods on sale for $30-$50 off MSRP t...
Best Buy is offering a $30-$50 discount on Apple HomePods this weekend on their online store. The HomePod mini is on sale for $69.99, $30 off MSRP, while Best Buy has the full-size HomePod on sale... Read more
Limited-time sale: 13-inch M3 MacBook Airs fo...
Amazon has the base 13″ M3 MacBook Air (8GB/256GB) in stock and on sale for a limited time for $989 shipped. That’s $110 off MSRP, and it’s the lowest price we’ve seen so far for an M3-powered... Read more
13-inch M2 MacBook Airs in stock today at App...
Apple has 13″ M2 MacBook Airs available for only $849 today in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty is included,... Read more
New today at Apple: Series 9 Watches availabl...
Apple is now offering Certified Refurbished Apple Watch Series 9 models on their online store for up to $80 off MSRP, starting at $339. Each Watch includes Apple’s standard one-year warranty, a new... Read more
The latest Apple iPhone deals from wireless c...
We’ve updated our iPhone Price Tracker with the latest carrier deals on Apple’s iPhone 15 family of smartphones as well as previous models including the iPhone 14, 13, 12, 11, and SE. Use our price... Read more
Boost Mobile will sell you an iPhone 11 for $...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering an iPhone 11 for $149.99 when purchased with their $40 Unlimited service plan (12GB of premium data). No trade-in is required... Read more
Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more

Jobs Board

Operating Room Assistant - *Apple* Hill Sur...
Operating Room Assistant - Apple Hill Surgical Center - Day Location: WellSpan Health, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Read more
Solutions Engineer - *Apple* - SHI (United...
**Job Summary** An Apple Solution Engineer's primary role is tosupport SHI customers in their efforts to select, deploy, and manage Apple operating systems and Read more
DMR Technician - *Apple* /iOS Systems - Haml...
…relevant point-of-need technology self-help aids are available as appropriate. ** Apple Systems Administration** **:** Develops solutions for supporting, deploying, Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.