The interactions between applications, users and the Photon server are represented by data structures called events.
This chapter discusses:
For more information on the PhEvent_t structure, see the Photon Library Reference.
This section describes how to use PhEventEmit(), as well as:
The most general way for an application to emit an event is by calling PhEventEmit():
int PhEventEmit( PhEvent_t *event, PhRect_t *rects, void *data );
The arguments are as follows:
The Photon Manager sets the following members of the event structure after a copy of the event is enqueued to an application:
If the event-specific data isn't in contiguous memory, you may find PhEventEmitmx() more useful than PhEventEmit():
int PhEventEmitmx( PhEvent_t *event, PhRect_t *rects, int mxparts, struct _mxfer_entry *mx );
The return codes for PhEventEmit() and PhEventEmitmx() are:
These return codes are useful for applications that spend most of their time emitting events and want to retrieve an event only if there's one pending for them.
Sometimes an application needs to target an event directly at a specific region, without making the event travel through the event space before arriving at that region. You can use an inclusive event or a direct event to ensure that the targeted region sees the event.
For an inclusive event, do the following:
If you don't want an inclusive targeted event to continue through the event space, you must make the emitting region opaque to that type of event.
For a direct event, do the following:
If you want to send an event to a specific widget, you could call PhEventEmit() as described above, but you'll need to look after a lot of details, including making sure:
It's easier to call PtSendEventToWidget(). This function gives the event to the specified widget directly and without delay. It's much more deterministic and efficient than PhEventEmit().
The prototype is:
int PtSendEventToWidget( PtWidget_t *widget, PhEvent_t *event );
Sometimes you might need to simulate a key press in your application. Depending on what exactly you want to achieve, you can choose from several ways of generating key events:
event->emitter = Ph_DEV_RID;
The rectangle set should consist of a single pixel - if you're not using the window manager, or if PWM is set to use cursor focus, the position of that pixel determines which window the event will hit.
event->collector = rid; event->flags |= Ph_EVENT_DIRECT;
If you're creating a keyboard driver, the region you're emitting your events from should have the Ph_KBD_REGION flag set, and should belong to an input group. To create a region that belongs to an input group, set input_group in PhRegion_t to a nonzero value (the same that you will put in the events), and set the Ph_REGION_INPUT_GROUP flag in the fields argument to PhRegionOpen().
Emit the event directly to the device region:
region (event->collector = Ph_DEV_RID; event->flags |= Ph_EVENT_DIRECT;
Photon will re-emit the event as a regular Ph_EV_KEY event from the current position of the pointer.
When an event is emitted, the coordinates of its rectangle set are relative to the emitting region's origin. But when the event is collected, its coordinates become relative to the collecting region's origin. The Photon Manager ensures this happens by translating coordinates accordingly.
To collect events, applications call PhEventRead() or PhEventNext(). The PhGetRects() function extracts the rectangle set, and PhGetData() extracts the event's data portion.
A region can collect events only if portions of its region overlap with the emitting region. |
The Photon Manager compresses drag, boundary, and pointer events. That is, if an event of that type is pending when another event arrives, the new event will be merged with the unprocessed events. As a result, an application sees only the latest values for these events and is saved from collecting too many unnecessary events.
You'll need to work with events if the user can drag objects in your application.
There are two types of dragging:
Dragging is done in two steps:
These steps are discussed in the sections that follow. For a more complex example, download the exdrag files from the /usr/free/qnx4/photon/examples directory in QUICS.
Where you initiate the dragging depends on how the user is meant to drag widgets. For example, if the user holds down the left mouse button on a widget to drag it, initiate dragging in the widget's Arm (Pt_CB_ARM) callback. Make sure that Pt_SELECTABLE is set in the widget's Pt_ARG_FLAGS resource.
Dragging is started by calling the PhInitDrag() function:
int PhInitDrag( PhRid_t rid, unsigned flags, PhRect_t *rect, PhRect_t *boundary, unsigned int input_group, PhDim_t *min, PhDim_t *max, PhDim_t *step );
The arguments are used as follows:
cbinfo->event->input_group
If Ph_DRAG_TRACK is included in flags, then opaque dragging is used; if Ph_DRAG_TRACK isn't included, outline dragging is used.
The following flags indicate which edge(s) of the dragging rectangle track the pointer:
The following example shows an Arm (Pt_CB_ARM) callback that initiates outline dragging:
/* Start dragging a widget */ /* AppBuilder Photon Code Lib */ /* Version 1.11 */ /* Standard headers */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> /* Toolkit headers */ #include <Ph.h> #include <Pt.h> #include <Ap.h> /* Local headers */ #include "globals.h" #include "abimport.h" #include "proto.h" int start_dragging( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { PhDim_t *dimension; PhRect_t rect; PhRect_t boundary; PtArg_t args[1]; /* eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; /* Set the dragging rectangle to the position and size of the widget being dragged. */ PtWidgetExtent (widget, &rect); /* Set the boundary for dragging to the boundary of the window. */ PtSetArg (&args[0], Pt_ARG_DIM, &dimension, 0); PtGetResources (ABW_base, 1, args); boundary.ul.x = 0; boundary.ul.y = 0; boundary.lr.x = dimension->w - 1; boundary.lr.y = dimension->h - 1; /* Initiate outline dragging (Ph_DRAG_TRACK isn't specified). */ PhInitDrag (PtWidgetRid (ABW_base), Ph_TRACK_DRAG, &rect, &boundary, cbinfo->event->input_group, NULL, NULL, NULL); /* Save a pointer to the widget being dragged. */ dragged_widget = widget; return( Pt_CONTINUE ); }
The above callback is added to the Arm (Pt_CB_ARM) callback of the widget to be dragged. It can be used for dragging any widget, so a pointer to the widget is saved in the global variable dragged_widget.
If you want to use opaque dragging, add the Ph_DRAG_TRACK flag to the call to PhInitDrag():
PhInitDrag( PtWidgetRid (ABW_base), Ph_TRACK_DRAG | Ph_DRAG_TRACK, &rect, &boundary, cbinfo->event->input_group, NULL, NULL, NULL );
To handle drag (Ph_EV_DRAG) events, you need to define a Raw (Pt_CB_RAW) callback.
The raw callback must be defined for the widget whose region was passed to PhInitDrag(), not for the widget being dragged. For the example given, the Raw callback is defined for the base window. |
As described in "Raw-event callbacks" in the Editing Resources and Callbacks in PhAB chapter, you use an event mask to indicate for which events your callback is to be called. For dragging, the event is Ph_EV_DRAG. The most commonly used subtypes for this event are:
If you're doing outline dragging, the event subtype you're interested in is Ph_EV_DRAG_COMPLETE. When this event occurs, your callback should:
Remember, the callback's widget parameter is a pointer to the container (the base window in the example), not to the widget being dragged. Make sure you pass the correct widget to PtSetResources() when setting the Pt_ARG_POS resource. |
For example, here's the Raw callback for the outline dragging initiated above:
/* Raw callback to handle drag events */ /* AppBuilder Photon Code Lib */ /* Version 1.11 */ /* Standard headers */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> /* Toolkit headers */ #include <Ph.h> #include <Pt.h> #include <Ap.h> /* Local headers */ #include "globals.h" #include "abimport.h" #include "proto.h" int end_dragging( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { PhDragEvent_t *dragData; PtArg_t args[1]; PhPoint_t new_pos; /* eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; /* Ignore all events until dragging is done. */ if (cbinfo->event->subtype != Ph_EV_DRAG_COMPLETE) { return (Pt_CONTINUE); } /* Get the data associated with the event. */ dragData = PhGetData (cbinfo->event); /* The rectangle in this data is the absolute coordinates of the dragging rectangle. We want to calculate the new position of the widget, relative to the dragging region. */ new_pos.x = dragData->rect.ul.x + cbinfo->event->translation.x; new_pos.y = dragData->rect.ul.y + cbinfo->event->translation.y; printf ("New position: (%d, %d)\n", new_pos.x, new_pos.y); /* Move the widget. */ PtSetArg (&args[0], Pt_ARG_POS, &new_pos, 0); PtSetResources (dragged_widget, 1, args); return( Pt_CONTINUE ); }
The callback for opaque dragging is similar to that for outline dragging-the only difference is the subtype of event handled:
if (cbinfo->event->subtype != Ph_EV_DRAG_MOVE) { return (Pt_CONTINUE); }