Event handlers
Event handlers are another mechanism used to inform the application of input actions by the user. While callbacks notify the application of high level interactions such as the selection of items in a list widget, event handlers notify the application of low level interactions, including the following:
Mouse pointer motion
Mouse button presses and releases
Individual key presses and releases
There are two common uses of event handlers. The first is for handling input in a drawing area widget. For example, in a graphical drawing application a drawing area widget would be used to display the drawing under construction. Event handlers would be registered to notify the application of pointer motion, mouse button, and key press events, allowing text strings to be edited and graphical objects to be positioned and changed using the mouse.
The second common use is for handling pop-up menus. An event handler is added for the ButtonMenuMask event. When the event handler is called, the application pops the menu up.
Mouse button 3 is used as the menu button. However, some platforms trigger the button menu event when the button is pressed, and others when the button is released. The ButtonMenuMask event hides this difference. It should be used, rather than the other button events, to support pop-up menus in a platform-independent manner.
 
*On some platforms it is possible for a button release event to be delivered without a corresponding button press event. Applications should be prepared to ignore such spurious button release events by only processing a button release event that is received after a matching button press event.
Registering an Event
Register event handlers using the addEventHandler:receiver:selector:clientData: method.
 
*The argBlock argument of a widget-creation message can only be used to set widget resources. The addEventHandler: message cannot be used within the create argBlock. Event handlers are usually registered immediately after the widget has been created, and before it is realized.
The addEventHandler:receiver:selector:clientData: method takes four parameters:
eventMask
A bit mask specifying which events to notify the receiver of
receiver
The object that receives the event handler message
selector
The 3-parameter event handler message selector
clientData
Optional data that is passed to the event handler when it is run
The eventMask is specified as the bitwise-OR of one or more of the bit masks described in the following table.
Table 34. Common widgets event masks
Event masks
Description
KeyPressMask
Keyboard key down events
KeyReleaseMask
Keyboard key up events
ButtonPressMask
Mouse button down events
ButtonReleaseMask
Mouse button up events
PointerMotionMask
All pointer motion events
Button1MotionMask
Pointer motion events while button 1 is down
Button2MotionMask
Pointer motion events while button 2 is down
Button3MotionMask
Pointer motion events while button 3 is down
ButtonMotionMask
Pointer motion events while any button is down
ButtonMenuMask
Button menu request events
Running an Event
When an event handler method is run, it is passed three arguments:
The widget to which the handler was added and in which the event occurred
The client data specified when the event handler was registered
An object describing the event, called the event
The following table describes the class hierarchy for event objects. Classes in italics are abstract classes.
Table 35. Event class hierarchy
Class hierarchy
Responsibility.
CwEvent
Defines common behavior for event data in event handlers.
 CwExposeEvent
Provides event data for expose events in expose callbacks (see Note below).
 CwInputEvent
Defines common behavior for button, key, and motion event objects.
  CwButtonEvent
Provides event data for mouse button-press/release events.
  CwKeyEvent
Provides event data for key-press/release events.
  CwMotionEvent 
Provides event data for mouse motion events.
 
*An expose event handler cannot be explicitly added to a widget. A CwExposeEvent object is passed to an application as part of the call data for an exposeCallback.
The following messages can be sent to the event object to retrieve information about the event. The methods for all events (CwEvent) include the following:
type
The type of event that occurred. This has one of the following values: ButtonPress, ButtonRelease, Expose, KeyPress, KeyRelease, and MotionNotify.
window
The CgWindow associated with the widget for which the event was generated.
display
The CgDisplay associated with the event.
For expose events (CwExposeEvent), the method include the following:
count
The number of expose events which remain for the affected CgWindow. A simple application might want to ignore all expose events with a nonzero count, and perform a full redisplay if the count is zero.
rectangle
A rectangle describing the damaged area, in the coordinate system of the affected CgWindow.
x
The x-coordinate of the origin of the damaged rectangle.
y
The y-coordinate of the origin of the damaged rectangle.
height
The height, in pixels, of the damaged rectangle.
width
The width, in pixels, of the damaged rectangle.
For input events (CwButtonEvent, CwKeyEvent, and CwMotionEvent), the methods are as follows:
state
A bit mask representing the logical state of modifier keys and pointer buttons just prior to the event. Possible bit masks include: ControlMask, ShiftMask, LockMask, Mod1Mask to Mod5Mask, and Button1Mask to Button3Mask.
x
The x-coordinate of the pointer, relative to the widget in which the event occurred.
y
The y-coordinate of the pointer, relative to the widget in which the event occurred.
point
x @ y
xRoot
A coordinate of the pointer, relative to the screen.
yRoot
A coordinate of the pointer, relative to the screen.
pointRoot
xRoot @ yRoot
time
The time, in milliseconds, at which the event occurred.
For mouse button events (CwButtonEvent), the methods are as follows:
button
The number of the button that was pressed or released (1, 2 or 3).
For key events (CwKeyEvent), the methods are as follows:
keysym
A constant describing the keyboard key that was pressed or released. These constants are found in the e CwConstants pool dictionary, and are prefixed with 'XK.'
character
The Character describing the keyboard key that was pressed or released, or nil if it does not represent a valid character.
Example
In the following example, a drawing area is created, and an event handler is added to notify the application of mouse button presses, key presses, and pointer motion. Label widgets are used to display information about the events. The variable labels would be implemented as an instance variable for the class.
| shell rowColumn label labels drawing |
shell := CwTopLevelShell
createApplicationShell: 'shell'
argBlock: [:w | w title: 'Event Handler Example'].
rowColumn := shell
createRowColumn: 'rowColumn'
argBlock: nil.
rowColumn manageChild.
labels := Array new: 3.
1 to: 3 do: [:i |
label := rowColumn
createLabel: 'label'
argBlock: nil.
label manageChild.
labels at: i put: label].
(labels at: 1) labelString: 'Position: '.
(labels at: 2) labelString: 'Button pressed at position: '.
(labels at: 3) labelString: 'Keysym of last pressed key: '.
drawing := rowColumn
createDrawingArea: 'drawing'
argBlock: [:w |
w
borderWidth: 1;
width: 300;
height: 300].
drawing
addEventHandler: ButtonPressMask | KeyPressMask | PointerMotionMask
receiver: self
selector: #eventHandler:clientData:event:
clientData: labels.
drawing manageChild.
shell realizeWidget
When an event occurs, the following method is run. Information about the event is determined from the event argument and is displayed in the label widgets.
eventHandler: widget clientData: clientData event: event
"Handle an input event."
 
| labels |
labels := clientData.
event type = MotionNotify
ifTrue: [(labels at: 1) labelString: 'Position: ',
event point printString].
event type = ButtonPress
ifTrue: [(labels at: 2) labelString: 'Button ', event
button printString, ' pressed at position: ',
event point printString].
event type = KeyPress
ifTrue: [(labels at: 3) labelString: 'Keysym of last pressed key: ',
event keysym printString].
Last modified date: 04/20/2020